Cómo actualizar el Widget de la aplicación con la vista de lista de una actividad
Sé que esto se ha pedido muchas veces pero pasé por la documentación de arriba a abajo, leí todas las respuestas aquí y ninguna de ellas ayudó. Para ser honesto, cada respuesta dice algo diferente acerca de cómo abordar esto.
Ahora volvamos a mi pregunta. Quiero actualizar la vista de lista de widgets de alguna actividad y he creado WidgetProvider#sendUpdateBroadcastToAllWidgets()
para este propósito que llamo de la actividad.
- Error de instalación: Error desconocido Aplicación para Android
- Android - Pasar un conjunto de clases entre actividades
- Descodificación de HttpEntity en el problema de codificación de cadenas android
- Java.text.ParseException: Fecha inestable: "2014-06-04" (en el desplazamiento 5)
- Pasar un valor de la actividad a hilo después de hilo ya está creado
Eventualmente llama a onUpdate()
para que la emisión sea recibida correctamente. Pero las vistas no se refrescan.
También intenté llamar AppWidgetManager#notifyAppWidgetViewDataChanged()
y actualizar los datos en WidgetFactory#onDataSetChanged()
pero el método nunca ha sido llamado.
Así que supongo que todo esto no funciona porque la fábrica de vistas remotas se almacena en caché, pero no sé cómo superar esto de forma fiable. ¿Alguna idea?
¿Y los contextos? Siempre tengo que suministrar uno, pero realmente no me importa mucho cuál. ¿Importa?
Gracias
PROVEEDOR
public class WidgetProvider extends AppWidgetProvider { public static void sendUpdateBroadcastToAllWidgets(Context context) { int allWidgetIds[] = AppWidgetManager.getInstance(context).getAppWidgetIds(new ComponentName(context, WidgetProvider.class)); Intent intent = new Intent(context, WidgetProvider.class); intent.setAction(AppWidgetManager.ACTION_APPWIDGET_UPDATE); intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS, allWidgetIds); context.sendBroadcast(intent); } @Override public void onUpdate(Context context, AppWidgetManager widgetManager, int[] widgetIds) { for (int id : widgetIds) { updateWidget(context, widgetManager, id); } super.onUpdate(context, widgetManager, widgetIds); } @Override public void onDeleted(Context context, int[] widgetIds) { WidgetPreferences prefs = new WidgetPreferences(context); for (int widgetId : widgetIds) { prefs.getWidgetPreferences(widgetId).edit().clear().commit(); } super.onDeleted(context, widgetIds); } private static void updateWidget(Context context, AppWidgetManager widgetManager, int widgetId) { RemoteViews views = new RemoteViews(context.getPackageName(), R.layout.widget); // set list adapter Intent serviceIntent = new Intent(context, WidgetService.class); serviceIntent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, widgetId); serviceIntent.setData(Uri.parse(serviceIntent.toUri(Intent.URI_INTENT_SCHEME))); views.setRemoteAdapter(android.R.id.list, serviceIntent); views.setEmptyView(android.R.id.list, android.R.id.empty); // set widget title WidgetDataCategory category = new WidgetPreferences(context).getSavedCategory(widgetId); views.setTextViewText(R.id.titleText, context.getString(category.titleResourceId())); // set onclick listener - we create a pending intent template and when an items is clicked // the intent is filled with missing data and sent Intent startActivityIntent = new Intent(context, SimplePersonDetailActivity.class); startActivityIntent.setData(Uri.parse(startActivityIntent.toUri(Intent.URI_INTENT_SCHEME))); startActivityIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_SINGLE_TOP); startActivityIntent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, widgetId); PendingIntent pendingIntent = PendingIntent.getActivity(context, 0, startActivityIntent, PendingIntent.FLAG_UPDATE_CURRENT); views.setPendingIntentTemplate(android.R.id.list, pendingIntent); // all hail to Google widgetManager.updateAppWidget(widgetId, views); } }
FÁBRICA
public class WidgetFactory implements RemoteViewsService.RemoteViewsFactory { private Context context; private List<Person> people = new ArrayList<>(); public WidgetFactory(Context context, Intent intent) { this.context = context; int widgetId = intent.getIntExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, AppWidgetManager.INVALID_APPWIDGET_ID); if (widgetId != AppWidgetManager.INVALID_APPWIDGET_ID) { WidgetPreferences prefs = new WidgetPreferences(context); WidgetDataCategory category = prefs.getSavedCategory(widgetId); int numberOfItemsToShow = prefs.getSavedLimit(widgetId); people = category.filterAndSlice(new PersonDao(context).getAllForGroup(Constants.SIMPLE_GROUP_ID), numberOfItemsToShow); } } @Override public void onCreate() {} @Override public void onDataSetChanged() {} @Override public void onDestroy() {} @Override public int getCount() { return people.size(); } @Override public RemoteViews getViewAt(int position) { Person person = people.get(position); BigDecimal amount = ListViewUtil.sumTransactions(new TransactionDao(context).getAllForPerson(person)); RemoteViews remoteViews = new RemoteViews(context.getPackageName(), R.layout.item_widget); remoteViews.setTextViewText(R.id.nameText, person.getName()); remoteViews.setTextViewText(R.id.amountText, MoneyFormatter.withoutPlusPrefix().format(amount)); // fill details for the onclick listener (updating the pending intent template // set in the WidgetProvider) Intent listenerIntent = new Intent(); listenerIntent.putExtra(Constants.PERSON_ID, people.get(position).getId()); remoteViews.setOnClickFillInIntent(R.id.widgetItem, listenerIntent); return remoteViews; } @Override public RemoteViews getLoadingView() { return null; } @Override public int getViewTypeCount() { return 1; } @Override public long getItemId(int position) { return position; } @Override public boolean hasStableIds() { return true; } }
- Android: Iniciar el primer plano no mostrará la notificación correctamente
- error de compilador: "El cursor no se puede resolver a un tipo"
- Android: cómo acceder a la tabla de contactos de SIM con el SDK?
- Uso de fuentes personalizadas para todo el texto de la aplicación que no funciona con Lollipop
- El método getString (int) no está definido para el tipo Apps
- Android / Java Append String + int
- Ejecución fallada para la tarea: app: compileDebugJavaWithJavac en Android Studio
- Google App Engine y Android (OAuth, C2DM o Cloud Messaging)
Yo diría que notifyAppWidgetViewDataChanged
método debería funcionar para usted.
Tienes que crear AppWidgetManager
y obtener appWidgetIds
y luego llamar a notifyAppWidgetViewDataChanged
en tu AppWidgetManager
.
Pseudo Código,
AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(context); int appWidgetIds[] = appWidgetManager.getAppWidgetIds( new ComponentName(context, WidgetProvider.class)); appWidgetManager.notifyAppWidgetViewDataChanged(appWidgetIds, R.id.listview);
Para obtener más información, puede comprobar mi respuesta aquí que contiene demo en github.
Tuve una implementación widget en mi proyecto. He modificado el código debajo de modo que los datos en widget puedan ser cambiados de uno de mi actividad en la aplicación. Sólo muestra el código esencial para su caso de uso específico.
Aquí estoy teniendo un botón con texto en mi widget. A través del botón de inicio de sesión haga clic en mi Actividad, estoy modificando el texto del botón en mi widget
A continuación se muestra mi clase AppWidgetProvider.java
public class AppWidgetTrackAsset extends AppWidgetProvider{ @Override public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) { // Perform this loop procedure for each App Widget that belongs to this provider final int N = appWidgetIds.length; for (int i=0; i<N; i++) { int appWidgetId = appWidgetIds[i]; // Create an Intent to launch Activity Intent intent = new Intent(context, WidgetAlertActivity.class); PendingIntent pendingIntent = PendingIntent.getActivity(context, 0, intent, 0); // Get the layout for the App Widget and attach an on-click listener // to the button RemoteViews views = new RemoteViews(context.getPackageName(), R.layout.app_widget_track_asset); views.setOnClickPendingIntent(R.id.sosButton, pendingIntent); // Tell the AppWidgetManager to perform an update on the current app widget appWidgetManager.updateAppWidget(appWidgetId, views); } } @Override public void onReceive(Context context, Intent intent) { super.onReceive(context, intent); Log.v(Constants.WIDGET_LOG, "onReceive called with " + intent.getAction()); if (intent.getAction().equals("update_widget")) { // widget update started RemoteViews remoteViews = new RemoteViews(context.getPackageName(), R.layout.app_widget_track_asset); // Update text , images etc remoteViews.setTextViewText(R.id.sosButton, "My updated text"); // Trigger widget layout update AppWidgetManager.getInstance(context).updateAppWidget( new ComponentName(context, AppWidgetTrackAsset.class), remoteViews); } } @Override public void onEnabled(Context context) { // Enter relevant functionality for when the first widget is created } @Override public void onDisabled(Context context) { // Enter relevant functionality for when the last widget is disabled } }
A continuación se muestra mi Actividad donde estoy actualizando el texto del botón del widget al hacer clic en mi botón de inicio de sesión
LoginActivity.java
public class LoginActivity extends AppCompatActivity implements View.OnClickListener{ Button loginButton; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_login); loginButton=(Button)findViewById(R.id.loginButton); loginButton.setOnClickListener(this); } @Override public void onClick(View v) { if(v.getId() == R.id.loginButton){ updateWidget(); } } private void updateWidget(){ try { Intent updateWidget = new Intent(this, AppWidgetTrackAsset.class); updateWidget.setAction("update_widget"); PendingIntent pending = PendingIntent.getBroadcast(this, 0, updateWidget, PendingIntent.FLAG_CANCEL_CURRENT); pending.send(); } catch (PendingIntent.CanceledException e) { Log.e(Constants.UI_LOG,"Error widgetTrial()="+e.toString()); } } }
El diseño del widget de la aplicación es así
app_widget_track_asset.xml
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:background="@drawable/widgetbackground" android:padding="@dimen/widget_margin"> <Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:id="@+id/sosButton" android:text="SOS" android:textSize="20sp" android:layout_centerHorizontal="true" android:layout_centerVertical="true" /> </RelativeLayout>
A continuación se muestra la parte esencial del archivo de manifiesto para el widget
<receiver android:name=".appwidget.AppWidgetTrackAsset"> <intent-filter> <action android:name="android.appwidget.action.APPWIDGET_UPDATE" /> </intent-filter> <meta-data android:name="android.appwidget.provider" android:resource="@xml/app_widget_track_asset_info" /> </receiver>
- ActionBarSherlock Ítem Icono de ancho extraño con Android 4.3
- ¿Hay alguna manera de reemplazar o silenciar el sonido del obturador de la cámara en android?