Reputation: 16414
I'm adding a widget to an old app which I'm updating from a service I'm using to poll for data in the background (on an alarm). I update the widget every time the service gets a result. This is currently working correctly.
// Called from inside my service when it has results
private void updateWidget(List<Earthquake> earthquakes) {
AppWidgetManager manager = AppWidgetManager.getInstance(this);
int[] appWidgetIds = manager.getAppWidgetIds(new ComponentName(this, WhatsShakingWidgetProvider.class));
if (appWidgetIds == null || appWidgetIds.length == 0)
return;
Earthquake earthquake = earthquakes.get(0);
RemoteViews views = new RemoteViews(getPackageName(), R.layout.widget_detail);
// Update views
views.setTextViewText(R.id.widget_detail_latest_magnitude, earthquake.getFormattedMagnitude());
// etc...
// Update each widget
for(int appWidgetId : appWidgetIds) {
manager.updateAppWidget(appWidgetId, views);
}
}
This polling service is optional; it can be turned on or off in the app's settings.
If the service is off when the user adds the widget, the widget_error
layout is shown, as expected. The user can tap on the widget to enter the settings and turn the background updates on. When they do this (turn the setting on or off), I broadcast ACTION_APPWIDGET_UPDATE
. The widget enters onUpdate
correctly, and is updated correctly by the service the next time it runs (I've set it up so the widget triggers a service call in onUpdate
- see below).
The widget does not correctly display the widget_error
layout when the service becomes disabled after being enabled - it leaves the old layout in place, even though all the disabled-case code is run.
This is the code that gets called when the user toggles the setting (Source):
// If our user has widgets, we should update those - let the widget do the updating depending on the prefs, though.
Intent intent = new Intent(this, WhatsShakingWidgetProvider.class);
intent.setAction(AppWidgetManager.ACTION_APPWIDGET_UPDATE);
// Use an array and EXTRA_APPWIDGET_IDS instead of AppWidgetManager.EXTRA_APPWIDGET_ID,
// since it seems the onUpdate() is only fired on that:
int[] ids = { R.xml.widget_info };
intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS, ids);
sendBroadcast(intent);
And this is the code in onUpdate
which should be updating the widgets, but isn't:
@Override
public void onUpdate(Context context, AppWidgetManager appWidgetManager,
int[] appWidgetIds) {
super.onUpdate(context, appWidgetManager, appWidgetIds);
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
boolean backgroundUpdatesEnabled = prefs.getBoolean(PreferenceActivity.KEY_PREF_ALLOW_BG_NOTIFICATIONS,
DefaultPrefs.BG_NOTIFICATIONS_ENABLED);
if (!backgroundUpdatesEnabled) {
RemoteViews views = new RemoteViews(context.getPackageName(), R.layout.widget_error);
// Update click to take to preferences
Intent intent = new Intent(context, PreferenceActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
PendingIntent pendingIntent = PendingIntent.getActivity(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
views.setOnClickPendingIntent(R.id.widget_error_parent_container, pendingIntent);
// Update each widget
appWidgetManager.updateAppWidget(appWidgetIds, views);
} else {
// Let's get some data for the user! Service does the work of updating the views.
WakefulIntentService.sendWakefulWork(context, GeonetService.class);
}
}
There are no errors logged in Logcat. Stepping through this, I correctly enter each part of the if
when expected (that is, if the user turned the setting off, then I create RemoteViews views
as widget_error
, otherwise I start the service).
Why does the widget_error
layout display correctly the first time through onUpdate
, but not when the user enables, then disables, the background update setting?
I've tried wrapping this in a RelativeLayout
and setting the visibility of the error message/the content, but that exhibited the same behaviour - I couldn't get the error message to show back up after initially hiding it.
Upvotes: 0
Views: 122
Reputation: 16414
I ended up duplicating the code in two places (the preferences activity and the widget provider) and it worked. The only variable appears to be the Context
object.
It appears that for some reason the Context
instance you get in the AppWidgetProvider
(that is, in onUpdate
) only works the first time - or, doesn't work when I send the broadcast myself. I'm not sure why.
I pulled my duplicated code out to a separate class and just pass in the Context
instance I have available, whether it's the Service
, an Activity
, or the AppWidgetProvider
(which is a BroadcastReceiver
). This correctly updates the widget, and I can call it from anywhere I have a Context
.
Upvotes: 1