Unable to update Android widget from BroadcastReceiver

I want to encode an application that displays some information in widgets that need to be updated from time to time. From time to time, this means that I use the alarm clock timer to trigger a periid update. So the problem is: intent.getIntArrayExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS); is zero for broadcast receiver intentions.

Here is my widget provider:

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

and this caused a problem with BroadcastReceiver:

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

Can this be solved?

+4
source share
4 answers

When the system calls your implementation of AppWidgetProvider , it fills the intent with these additional functions.

But when it calls your broadcast receiver, which has nothing to do with widgets, it does not fill out this unnecessary intent.

You will need to use a different method to pass identifiers. Maybe you can fill them in Intent , which is triggered when an alarm is triggered?

0
source

Lol, I have my answer ...

Just replace:

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

by

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

so I changed the broadcast receiver to the following:

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

this still works - since the first alarm timer (should be) set without knowing the widget-id array. (e.g. using onclickhandler) ... is there a way to do this right?

0
source

Surprise: why don't you just override the onReceive () method of WidgetProvider? Since the AppWidgetProvider application is extended from BroadcastReceiver, it is completely legal if you call super.onReceive ().

The intent that you get through onReceive () contains widget identifiers as optional if it was called by AppWidgetHost (Launcher). If you call it yourself, you need to add the necessary additional services yourself.

It looks like an elegant way to launch WidgetProvider from any other action, while preserving the original functionality.

Remember: AppWidgetProvider is a handy class that makes widget development easier, but basically it's just BroadcastReceiver.

I solved it like this:

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

And in your activity / fragment:

  /** * 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); } 

It looks a bit complicated because I have a dynamic resizable widget with JellyBean and a fixed widget size below this OS version, but the solution should be clear.

Even simpler would be to simply send the android .appwidget.action.APPWIDGET_UPDATE broadcast, just like Launcher, to directly call onUpdate () of your WidgetProvider.

Then there is a completely different option available: let the Updateservice independently obtain the WidgetIDs, so there is no need to extract them from the update intent. This is normal if all widgets basically use the same configuration and need to be updated if something changes in the configuration:

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

Yes, I had to use ArrayUtils to combine arrays ... leaves room for improvement; -)

0
source

Source: https://habr.com/ru/post/1383901/


All Articles