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:
- Emulador de Android 4.2.2 no se muestra agregar opción de widget en la pantalla de bloqueo
- El widget desaparece cada vez que se actualiza la aplicación en dispositivos Samsung
- Android: intento de abrir el menú contextual del widget
- Buscar ID de widget de la pantalla de inicio
- Android Studio, Problemas de reproducción
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?
- Cómo agregar widgets múltiples en una aplicación?
- ¿Cómo actualizar los widgets de un servicio?
- Widget de Android con ListView no carga elementos correclty
- Estilos de widgets personalizados de Android: cómo colocarlos en un espacio de nombres?
- Los bordes redondos de Android en la barra de progreso en forma de anillo
- Parámetro de vista de Android para el método OnClickListener
- Actualizar ViewFlipper's Child View cuando ViewFlipper es como Widget
- Android: Apertura de actividad incorrecta del widget
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 😉
- Android 2.2: ¿Cómo actualizar las vistas de texto automáticamente con un temporizador?
- Roboguice y simulacros: ¿Cómo roboguice inyectar un servicio de simulacro cuando la prueba, pero utiliza el REAL de lo contrario?