Android: ¿Cómo obligar a la actualización de todos los widgets de un tipo particular

He visto muchas preguntas en este sentido, y sigo viendo la misma respuesta una y otra vez. No quiero tener que tener un servicio para cada tipo de widget de mi aplicación, especialmente viendo como mi aplicación ya tiene 2 servicios persistentes.

En concreto, si uno de mis servicios existentes ve que los datos han cambiado, quiero actualizar mis widgets. Hacer esto en un temporizador es molesto, ya que podría ser días entre actualizaciones o puede haber varios dentro de una hora. Quiero que mis widgets siempre muestren información actualizada.

Diseño de widgets Android parece funcionar en la base de que su widget extrae información cuando lo quiere, creo que hay muchos escenarios razonables donde una actividad puede desear enviar datos a un widget.

Lea la respuesta a continuación para saber cómo he trabajado cómo hacer precisamente esto. Por lo que puedo ver no hay efectos adversos si se hace correctamente.

Para obligar a nuestros widgets a un determinado proveedor de widgets a actualizar, tendremos que hacer lo siguiente:

  • Configurar nuestro proveedor para recibir una difusión especializada
  • Enviar la difusión especializada con:
    1. Todas las ID de widget actual asociadas con el proveedor
    2. Los datos a enviar
    3. Claves a las que sólo responde nuestro proveedor (¡Importante!)
  • Obteniendo nuestro widget para actualizar en clic (sin un servicio!)

Paso 1: configure nuestro AppWidgetProvider

No voy a pasar por los detalles de la creación de la información del archivo xml o cambios en el manifiesto de Android – si no sabes cómo crear un widget correctamente, entonces hay un montón de tutoriales que hay que leer primero.

Aquí hay un ejemplo de la clase AppWidgetProvider :

 public class MyWidgetProvider extends AppWidgetProvider { public static final String WIDGET_IDS_KEY ="mywidgetproviderwidgetids"; public static final String WIDGET_DATA_KEY ="mywidgetproviderwidgetdata"; } @Override public void onReceive(Context context, Intent intent) { if (intent.hasExtra(WIDGET_IDS_KEY)) { int[] ids = intent.getExtras().getIntArray(WIDGET_IDS_KEY); if (intent.hasExtra(WIDGET_DATA_KEY)) { Object data = intent.getExtras().getParcelable(WIDGET_DATA_KEY); this.update(context, AppWidgetManager.getInstance(context), ids, data); } else { this.onUpdate(context, AppWidgetManager.getInstance(context), ids); } } else super.onReceive(context, intent); } @Override public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) { update(context, appWidgetManager, appWidgetIds, null); } //This is where we do the actual updating public void update(Context context, AppWidgetmanager manager, int[] ids, Object data) { //data will contain some predetermined data, but it may be null for (int widgetId : ids) { . . //Update Widget here . . manager.updateAppWidget(widgetId, remoteViews); } } 

Paso 2 – Envío de la emisión

Aquí podemos crear un método estático que hará que nuestros widgets se actualicen. Es importante que usemos nuestras propias claves con la acción de actualización del widget, si usamos AppWidgetmanager.EXTRA_WIDGET_IDS no solo romperemos nuestro propio widget, sino también otros.

 public static void updateMyWidgets(Context context, Parcelable data) { AppWidgetManager man = AppWidgetManager.getInstance(context); int[] ids = man.getAppWidgetIds( new ComponentName(context,MyWidgetProvider.class)); Intent updateIntent = new Intent(); updateIntent.setAction(AppWidgetManager.ACTION_APPWIDGET_UPDATE); updateIntent.putExtra(MyWidgetProvider.WIDGET_ID_KEY, ids); updateIntent.putExtra(MyWidgetProvider.WIDGET_DATA_KEY, data); context.sendBroadcast(updateIntent); } 

Si utiliza este método con varios proveedores Asegúrese de que utilizan diferentes claves. De lo contrario, puede encontrar widget a código de actualización del widget b y que puede tener algunas consecuencias extrañas.

Paso 3: actualizar al hacer clic

Otra cosa agradable de hacer es conseguir nuestro widget actualizar magiacally cada vez que se hace clic. Agregue el código siguiente al método de actualización para lograr esto:

 RemoteViews views = new RemoteViews(context.getPackageName(),R.layout.mywidget_layout); Intent updateIntent = new Intent(); updateIntent.setAction(AppWidgetManager.ACTION_APPWIDGET_UPDATE); updateIntent.putExtra(myWidgetProvider.WIDGET_IDS_KEY, ids); PendingIntent pendingIntent = PendingIntent.getBroadcast( context, 0, updateIntent, PendingIntent.FLAG_UPDATE_CURRENT); views.setOnClickPendingIntent(R.id.view_container, pendingIntent); 

Este código hará que el método onUpdate sea llamado cada vez que se hace clic en el widget.

Notas

  • Cualquier llamada a updateWidgets () hará que todas las instancias de nuestro widget se actualicen.
  • Al hacer clic en el widget, todas las instancias de nuestro widget se actualizarán
  • NO SE NECESITA SERVICIO
  • Por supuesto, tenga cuidado de no actualizar a menudo – las actualizaciones de widget usan la energía de la batería.
  • Tenga en cuenta que la difusión es recibida por TODOS los proveedores de widgets y sus claves especiales que garantizan que solo nuestros widgets se actualicen.

Lo siento al OP por una respuesta tardía, pero para cualquier otra persona, puedes usar un método como este para actualizar todos los widgets de tu aplicación de un tipo en particular (diseño y clase):

 public static void updateAllWidgets(final Context context, final int layoutResourceId, final Class< ? extends AppWidgetProvider> appWidgetClass) { RemoteViews remoteViews = new RemoteViews(context.getPackageName(), layoutResourceId); AppWidgetManager manager = AppWidgetManager.getInstance(context); final int[] appWidgetIds = manager.getAppWidgetIds(new ComponentName(context, appWidgetClass)); for (int i = 0; i < appWidgetIds.length; ++i) { manager.updateAppWidget(appWidgetIds[i], remoteViews); } } 

Lo que hace es crear una RemoteViews para su diseño y luego se apodera de la AppWidgetManager y encuentra todos los widgets de la aplicación para la clase que proporcionó, itera sobre ellos y los actualiza.

Cada vez que se trata de tipos es bastante fácil simplemente trabajar con la estática. Y, si lo que deseas es que sucedan cosas específicas basadas en un "disparador", siempre recomendaría la programación basada en eventos … Los intentos son esencialmente el "evento" predeterminado en Android (para pasar datos en tu evento, asegúrate de que el objeto implemente La interfaz Parcelable).

Hay muchos muchos ejemplos de estos conceptos en los diversos foros y documentación de SDK.

  • Los botones del widget Android dejan de funcionar
  • Desmarcando RadioButton - método alternativo
  • Android 3.0, Vista previa de widgets
  • ¿Cómo crear una imagen de fondo nítida para 1x1 widget Android?
  • Cómo llamar manualmente `onUpdate` desde el propio widget
  • Android Widget: vista previaEstación de imagen
  • Actualizar sólo el ID de widget Android actual en el método de actualización.
  • Widget de aplicación setImageViewUri no actualiza la imagen
  • Iniciar VPNService desde dentro de widget android
  • Android equivalente de UIWebView en Xcode
  • ¿Cómo usar una tipografía personalizada en un widget?
  • FlipAndroid es un fan de Google para Android, Todo sobre Android Phones, Android Wear, Android Dev y Aplicaciones para Android Aplicaciones.