My widget is comprised of 2 buttons and a listview displaying data. Most times, when the widget provider's onUpdate method is called, everything loads normally and everyone is happy.
However I've noticed sometimes after the update method is called, the widget just completely fails to load its data. The listview is empty, and all of the buttons are non-responsive. It's as if I initialized the layout into the widget, but none of the pending intents nor the adapter for list were set.
I logged everything and found that this isn't the case. The pending intents ARE created, as is the list adapter, every time, including the random time when it fails. For a long time I thought it had to do with how the list data is populated into the adapter, but seeing it work every single time, coupled with the fact that the button intents don't work as well leads me to believe the method updateAppWidget(ComponentName, RemoteViews) is what is failing. However, there are no error stacks to help me confirm this.
Here is the code which runs in a separate service called by the AppWidgetProvider's onUpdate method:
@SuppressWarnings("deprecation")
private void updateWidget(int[] ids) {
AppWidgetManager widgetManager = AppWidgetManager.getInstance(this);
int[] widgetIds = widgetManager.getAppWidgetIds(new ComponentName(this, WidgetReceiver.class));
for (int currentWidgetId : widgetIds) {
RemoteViews widget = new RemoteViews(this.getPackageName(), R.layout.widget_layout);
Intent intent = new Intent(this, WidgetService.class);
intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, currentWidgetId);
intent.putExtra("random", randomNumber);
randomNumber++;
intent.setData(Uri.parse(intent.toUri(Intent.URI_INTENT_SCHEME)));
widget.setRemoteAdapter(currentWidgetId, android.R.id.list, intent);
Intent clickIntent = new Intent(this, DetailsActivity.class);
PendingIntent pending = PendingIntent.getActivity(this, 0, clickIntent, PendingIntent.FLAG_UPDATE_CURRENT);
widget.setPendingIntentTemplate(android.R.id.list, pending);
Intent settingsIntent = new Intent(this, WidgetSettingsActivity.class);
settingsIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
settingsIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
PendingIntent settingsPending = PendingIntent.getActivity(this, 0, settingsIntent, PendingIntent.FLAG_UPDATE_CURRENT);
widget.setOnClickPendingIntent(R.id.widget_settings, settingsPending);
Intent mainIntent = new Intent(this, MainActivity.class);
PendingIntent mainPending = PendingIntent.getActivity(this, 0, mainIntent, PendingIntent.FLAG_UPDATE_CURRENT);
widget.setOnClickPendingIntent(R.id.widget_logo, mainPending);
ComponentName widgetCompName = new ComponentName(this, WidgetReceiver.class);
widgetManager.updateAppWidget(widgetCompName, widget);
}
}
What is most frustrating about this bug is that I can't reliably recreate it. Sometimes I get (un)lucky and it shows it ugly head, other times (the majority of the time) it works perfectly.
Another thing that I thought was interesting is that I've seen the same exact problem in Facebook's widget. Due to NDA I can't show a screen of my app when it fails, but I can show a screen of Facebook's identical problem:
When Facebook's widget looks like this, it has the exact same issues as mine. No data loaded, all buttons are unresponsive.
For both Facebook and my widget, a subsequent update interval will usually make the problem go away.
As much as I appreciate that I'm not the only one who is running into this, I still don't want to release until I fix this. Has anyone here run into this, and better yet found a solution, or even a cause of the problem? Thanks for helping.
EDIT: Something interesting. I ran an experiment where I set the update interval to a full day rather than every 30 minutes. My hypothesis was that maybe the update method wasn't the cause, it was something else which was causing the widget to become blank and unresponsive.
Sure enough, after about 2 hours, I checked my phone and the widget was dead, despite no update method being called. This would lead me to believe that something else is causing this problem, NOT widgetManager.updateAppWidget(widgetCompName, widget);
like I previously thought.
I know that a configuration change can cause the widget to be rebuilt, and thus it is possible that it can fail. However, I already use the Service class's onConfigurationChanged method to reload the widget if necessary. Is there another case like configuration change which can cause the widget to destroy and recreate itself?