No se puede actualizar el widget android desde BroadcastReceiver

Quiero codificar una aplicación que muestra alguna información en un widget, que debería actualizarse de vez en cuando. De vez en cuando significa que utilizo un temporizador de alarma para activar una actualización peroidica. Así pues, el problema: intent.getIntArrayExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS); Es nulo para la intención de los receptores de difusión.

Aquí está mi proveedor de widgets:

 public class MyWidgetProvider extends AppWidgetProvider { public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) { final int N = appWidgetIds.length; for(int i=0; i<N; i++) { int widgetId = appWidgetIds[i]; RemoteViews rViews = new RemoteViews(context.getPackageName(), R.layout.widget_layout); Intent intent = new Intent(context.getApplicationContext(), TrafficService.class); intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS, appWidgetIds); rViews.setTextViewText(R.id.TextView01, "" + System.currentTimeMillis()); appWidgetManager.updateAppWidget(widgetId, rViews); } } } 

Y este es el BroadcastReceiver causando el problema:

 public class TimeIntervalReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { // set new alarm timer (code cut out) AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(context.getApplicationContext()); // PROBLEM BELOW! int[] appWidgetIds = intent.getIntArrayExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS); if(appWidgetIds == null) Log.d("TRAFFIC", "oh SHIT"); if(appWidgetIds != null && appWidgetIds.length > 0) { for(int widgetId : appWidgetIds) { RemoteViews rViews = new RemoteViews(context.getPackageName(), R.layout.widget_layout); rViews.setTextViewText(R.id.TextView01, "some data"); appWidgetManager.updateAppWidget(widgetId, rViews); } } } } 

¿Es esto aún solucionable?

Cuando el sistema llama a la implementación de AppWidgetProvider , llena la intención con estos extras.

Pero cuando llama a su receptor de difusión que no tiene nada que ver con el widget, no llena este extra en la intención.

Deberá utilizar otro método para transferir los ID. Tal vez usted podría llenarlos en la Intent que se dispara como la alarma de incendios?

Lol, tengo mi respuesta …

Simplemente reemplace:

 int[] appWidgetIds = intent.getIntArrayExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS); 

por

 ComponentName thisWidget = new ComponentName(getApplicationContext(),MyWidgetProvider.class); int[] appWidgetIds = appWidgetManager.getAppWidgetIds(thisWidget); 

Así que cambié el receptor de la difusión a la siguiente:

 public class TimeIntervalReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { Calendar c = Calendar.getInstance(); c.add(Calendar.SECOND, Config.UPDATE_RATE); Date d = new Date(c.getTimeInMillis()); AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(context.getApplicationContext()); int[] appWidgetIds = intent.getIntArrayExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS); if(appWidgetIds == null) Log.d("TRAFFIC", "oh SHIT"); // triggers :( if(appWidgetIds != null && appWidgetIds.length > 0) { for(int widgetId : appWidgetIds) { RemoteViews rViews = new RemoteViews(context.getPackageName(), R.layout.widget_layout); rViews.setTextViewText(R.id.TextView01, "someupdateddata"); appWidgetManager.updateAppWidget(widgetId, rViews); } } Intent i = new Intent(context, TimeIntervalReceiver.class); i.putExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS, appWidgetIds); // here i'd add the existing widget ids... PendingIntent sender = PendingIntent.getBroadcast(context, 0, i, PendingIntent.FLAG_UPDATE_CURRENT); AlarmManager aManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE); aManager.set(AlarmManager.RTC, d.getTime(), sender); } } 

Esto todavía dispara – porque el primer temporizador de la alarma es (necesita ser) fijado sin saber el widget-id-array. (Por ejemplo, por un onclickhandler) … ¿hay alguna manera de hacer esto bien?

Preguntándose: ¿Por qué no acaba de anular el método onReceive () del WidgetProvider? Desde AppWidgetProvider se amplía de BroadcastReceiver, esto es perfectamente legal, siempre y cuando usted llama a super.onReceive ().

La Intención que obtienes a través de onReceive () contiene las ID de Widget como un Extra, si ha sido llamado por AppWidgetHost (Launcher). Si lo llama por su cuenta, tiene que agregar los extras necesarios por usted mismo.

Esto parece ser una forma elegante para activar el WidgetProvider de cualquier otra actividad, manteniendo la funcionalidad original de la misma.

Recuerde: AppWidgetProvider es una clase conveniente para facilitar el desarrollo de widgets, pero para el núcleo es sólo un BroadcastReceiver.

Lo resolví así:

 public class WidgetProvider extends AppWidgetProvider { public static final String ACTION_RESTART_SERVICE = "ACTION_RESTART_SERVICE"; @Override public void onReceive(Context context, Intent intent) { Log.d(TAG, "onEnabled() called."); if (intent.getAction() != null && intent.getAction().equals(WidgetProvider.ACTION_RESTART_SERVICE)) { // Start service Log.d(TAG, "ACTION_RESTART_SERVICE... Restarting service with designated update interval..."); Intent i = new Intent(context, UpdateWidgetService.class); service = startService(i, context, service); } else { // Other intent, call super class Log.d(TAG, "Not ACTION_RESTART_SERVICE... calling superclass onReceive()..."); super.onReceive(context, intent); } } } 

Y en su Actividad / Fragmento:

  /** * Restart the update service via WidgetProvider to reflect new profile and settings * @param context Context is required */ private void restartService(Context context) { Intent intent = new Intent(context, WidgetProvider.class); intent.setAction(WidgetProvider.ACTION_RESTART_SERVICE); if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN) { // Send intents to all widget provider classes intent.setClass(context, WidgetProviderSize1.class); getActivity().sendBroadcast(intent); intent.setClass(context, WidgetProviderSize2.class); getActivity().sendBroadcast(intent); intent.setClass(context, WidgetProviderSize3.class); getActivity().sendBroadcast(intent); intent.setClass(context, WidgetProviderSize4.class); getActivity().sendBroadcast(intent); intent.setClass(context, WidgetProviderSize5.class); getActivity().sendBroadcast(intent); } else getActivity().sendBroadcast(intent); } 

Parece un poco complicado porque tengo un widget de tamaño dinámico con JellyBean y tamaños de Widget fijos por debajo de la versión del sistema operativo, pero la solución debe ser clara.

Una solución aún más fácil podría ser simplemente enviar un android.appwidget.action.APPWIDGET_UPDATE difusión intención exactamente como un lanzador para activar el onUpdate () de su WidgetProvider directamente.

Entonces hay una opción totalmente diferente disponible: Deje que el servicio de actualización obtener los WidgetIDs por sí mismo, por lo que no hay necesidad de obtenerlos de la intención de actualización. Esto está bien si todos los widgets comparten básicamente la misma configuración y deberían actualizarse si algo cambia en la configuración:

  /** * Get all Widget IDs of WidgetProviders used by this app * @param appWidgetManager AppWidgetManager to use * @return Array of widget IDs */ private int[] getAppWidgetIDs(AppWidgetManager appWidgetManager) { int[] widgetIdsOfOneProviderSize1 = getAppIdsOfSingleProvider(appWidgetManager, WidgetProviderSize1.class); int[] widgetIdsOfOneProviderSize2 = getAppIdsOfSingleProvider(appWidgetManager, WidgetProviderSize2.class); int[] widgetIdsOfOneProviderSize3 = getAppIdsOfSingleProvider(appWidgetManager, WidgetProviderSize3.class); int[] widgetIdsOfOneProviderSize4 = getAppIdsOfSingleProvider(appWidgetManager, WidgetProviderSize4.class); int[] widgetIdsOfOneProviderSize5 = getAppIdsOfSingleProvider(appWidgetManager, WidgetProviderSize5.class); int[] widgetIdsOfOneProvider = getAppIdsOfSingleProvider(appWidgetManager, WidgetProvider.class); int allWidgetIds[] = new int[widgetIdsOfOneProviderSize1.length + widgetIdsOfOneProviderSize2.length + widgetIdsOfOneProviderSize3.length + widgetIdsOfOneProviderSize4.length + widgetIdsOfOneProviderSize5.length + widgetIdsOfOneProvider.length]; int index = 0; for (int id : widgetIdsOfOneProviderSize1) { allWidgetIds[index] = id; index ++; } for (int id : widgetIdsOfOneProviderSize2) { allWidgetIds[index] = id; index ++; } for (int id : widgetIdsOfOneProviderSize3) { allWidgetIds[index] = id; index ++; } for (int id : widgetIdsOfOneProviderSize4) { allWidgetIds[index] = id; index ++; } for (int id : widgetIdsOfOneProviderSize5) { allWidgetIds[index] = id; index ++; } for (int id : widgetIdsOfOneProvider) { allWidgetIds[index] = id; index ++; } return allWidgetIds; } private int[] getAppIdsOfSingleProvider(AppWidgetManager appWidgetManager, Class cls) { ComponentName thisWidget = new ComponentName(getApplicationContext(), cls); int[] widgetIdsOfOneProvider = appWidgetManager.getAppWidgetIds(thisWidget); return widgetIdsOfOneProvider; } 

Sí, debería haber usado ArrayUtils para juntar los arrays … deja espacio para mejorar 😉

  • ¿Hay herramientas de interfaz de usuario personalizadas para Android?
  • Implementar ListView en los widgets Android
  • Widget simple de Android que inicia la actividad
  • Problema con el widget de la aplicación de Android
  • Establecer switchStyle - obtener error recurso no encontrado - ¿por qué?
  • Android: LED no se enciende / apaga
  • Cómo actualizar un Widget dinámicamente (No esperar 30 min para que onUpdate se llame)?
  • Lista de contactos con contacto La foto crea problemas de rendimiento
  • Cómo construir un widget de pantalla de inicio de Android?
  • Coordenadas de la pantalla de inicio de Android y xy
  • Android: la adición de datos al intento falla al cargar la actividad
  • FlipAndroid es un fan de Google para Android, Todo sobre Android Phones, Android Wear, Android Dev y Aplicaciones para Android Aplicaciones.