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.

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; } } 

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> 
  • Envíe archivos grandes (de vídeo) desde Android a PHP Server
  • No puedo trabajar con Jackson
  • SetAlpha para ver programaticamente
  • Cómo activar mediante programación GPS en Android Cupcake
  • ¿Dónde se detendrá el código cuando se muera la aplicación desde el Administrador de tareas de Android
  • ¿Cómo sé si mi mensaje de GCM es lo suficientemente pequeño (<4kb) para enviar? (Cómo obtener el tamaño de la cadena?)
  • Pasa la referencia de objeto dentro de Intent sin implementar Serializable o Parcelable
  • ¿Hay alguna clase en Java similar a android.os.Handler en Android?
  • ¿Por qué se debe cerrar OutputStream después de inputtream en android
  • ¿Qué es una buena práctica para combinar sus clases?
  • Cómo obtener JSON Array dentro de JSON objeto?
  • FlipAndroid es un fan de Google para Android, Todo sobre Android Phones, Android Wear, Android Dev y Aplicaciones para Android Aplicaciones.