Turning on / off the receiver (CONNECTIVITY_CHANGE) causes APPWIDGET_UPDATE to be sent
I have a receiver listening android.net.conn.CONNECTIVITY_CHANGE
to update its appwidget when the connection is reestablished. This works great, but I get some weird behavior when I enable or disable my receiver via:
ComponentName receiver = new ComponentName(this, NetworkStateReceiver.class);
PackageManager pm = getPackageManager();
pm.setComponentEnabledSetting(receiver, PackageManager.COMPONENT_ENABLED_STATE_ENABLED,
PackageManager.DONT_KILL_APP);
When the state is changed, I also get a broadcast android.appwidget.action.APPWIDGET_UPDATE
to my appwidget receiver, causing my appwidget to update again after detecting a lost connection, and then twice when the connection returns (once intentionally from my NetworkStateReceiver and then again from the APPWIDGET_UPDATE
broadcast).
Also, it only seems to be on my 4.04 device and not on my 2.1 device.
Manifest for NetworkStateReceiver and AppWidgetProvider
<receiver
android:name=".AppWidgetProvider"
android:label="@string/widget_name" >
<intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
</intent-filter>
<meta-data
android:name="android.appwidget.provider"
android:resource="@xml/appwidget" />
</receiver>
<receiver
android:name=".NetworkStateReceiver"
android:enabled="false">
<intent-filter>
<action android:name="android.net.conn.CONNECTIVITY_CHANGE" />
</intent-filter>
</receiver>
I've tried several ways to get around this, but none of them is a very good solution.
I can ignore any update from the broadcast APPWIDGET_UPDATE
. In fact, I have been doing this since the update of my appwidget is done via the service via the alert manager or config activity on first creation. For some reason (and perhaps an indication of what's going on), the broadcast APPWIDGET_UPDATE
also causes my remote views to fall back to their XML state, since it was added the first time. Perhaps I could work around this by keeping an extra state that would include bitmaps. Not ideal.
I could constantly listen to the NetworkStateReceiver rather than enable / disable, but this is against Android guidelines and for good reasons as it means unnecessary broadcasts.
Any other ideas?
EDIT . Further explanation of my current workaround.
I cannot ignore the broadcast APPWIDGET_UPDATE
even if I use alarms to trigger my updates. This is because it APPWIDGET_UPDATE
also resets my widget to its original state since it was first added to the home screen. In cases where I have a connection, I can do double updates because all information can be re-populated. I also still have to do my own update as the bug seems to be device specific and unprotected devices still need to be updated.
In cases where I have no connectivity, I then restore the widget from a previously saved state. This means that every time I do a successful update, I also save everything to SharedPreferences so that it can be restored under one of these "forced updates" when the internet is not available to properly repopulate the data.
In mine, AppWidgetProvider
I do (simplified):
Intent intent = new Intent(context, WidgetUpdateService.class);
intent.putExtra("loadFromSaved", true); // this will be false when coming from AlarmManager
context.startService(intent);
WidgetUpdateService.onStartCommand () (also simplified):
if (intent.getExtras().getBoolean("loadFromSaved") {
widgetLoader.loadFromSavedData();
} else {
widgetLoader.load()
}
source to share
So, if I understand correctly, two different things are happening:
-
When network status change notification is enabled, you get additional
ACTION_APPWIDGET_UPDATE
broadcasts to yourAppWidgetProvider
.While this is not what one would expect (although I can imagine the coded thinking that the widgets would like to update when the network state changes), it is not outside of the specific behavior of the Android system and therefore our code must be robust for arbitrary calls
ACTION_WIDGET_UPDATE
. Tracking the appWidgetId list and the last state of each widget on that list is a common way of identifying new widgets and instantly needed updates while leaving another update in the timer mechanisms. -
As you put it: even if the update does nothing, the problem still occurs.
If yours
onUpdate
doesn't do anything, it means reinitialization has nothing to do withACTION_WIDGET_UPDATE
. Somewhere, somehow, your initialization code gets called when you don't expect it. Now this is a pain, especially if there is no reason for the code, it should be like this. However, I and others have experienced this, so I point you two:- My list of things that helped: Service re-created by AlarmManager
- Brief discussion and solution for services started unexpectedly (which in the case of services that manage widgets often means they are reinitialized): Android's onCreate service is called multiple times without calling onDestroy
When I ran into the problem myself, I spent a lot of time injecting code into my code to find out which parts of my code were called when it became clear that the system was restarting my service for no specific reason, but what is it was solved as described in these two links. If I had to pick one thing that I thought was key, it would execute the service in a separate process for other activities (including AppWidgetProvider
).
source to share