3

I have a receiver listening for android.net.conn.CONNECTIVITY_CHANGE so that I can update my appwidget when connectivity is restored. This works fine except I am getting some strange behavior when I enable or disabled 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 receive an android.appwidget.action.APPWIDGET_UPDATE broadcast to my appwidget's receiver causing my appwidget to update again after detecting connectivity lost, and then twice when connectivity is returned (Once intentionally from my NetworkStateReceiver and then again from the APPWIDGET_UPDATE broadcast).

Also, this only seems to happen 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 have tried a few ways to work around this, but none are very good solutions.

I can ignore any update from an APPWIDGET_UPDATE broadcast. Actually I do this already since all my appwidget updating happens through a service via an alarm manager or config activity when first created. For some reasons though (and perhaps indicative of whats going on), the APPWIDGET_UPDATE broadcast also causes my remoteviews to revert back to its XML state like its been added for the first time. I could probably work around that too by saving extra state, which would include bitmaps. Not ideal.

I could have the NetworkStateReceiver listen all the time instead of enableing/disabling, but this goes against Android's recommendations and for good reasons since it means unnecessary broadcasts.

Other ideas?

EDIT: Further explanation of my current workaround.

I can't ignore the APPWIDGET_UPDATE broadcast even though I use alarms to trigger my updates. This is because the APPWIDGET_UPDATE also resets my widget to its initial state like its been added to the homescreen for the first time. In cases where I have a connection I can do double updates because all the info can be re-populated. I also still have to do my own update since the bug seems device specific and non-affected devices still need an update.

In cases where I do not have connectivity, I then restore the widget from earlier saved state. This means that every time I do a successful update, I also save everything to SharedPreferences so it can be restored under one of these "forced updates" when internet isn't available to properly re-populate the data.

In my 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()
}
paul
  • 786
  • 1
  • 7
  • 18
  • Paul - I have exactly the same issue. Its driving me crazy!..... – electricSunny Apr 04 '13 at 03:51
  • I still haven't found a good solution. I am working around it right now by saving extra state. Please post if you figure something out! I saw this [bug report](https://code.google.com/p/android/issues/detail?id=21635) which is different, but perhaps related. – paul Apr 04 '13 at 04:21
  • Paul - I'm still no further forward. I'd be interested to hear your workaround for this, saving extra state. Would you please mind sharing? ta – electricSunny Apr 07 '13 at 20:30
  • Funkatron - I may actually switch back to leaving the NetworkStateReceiver listening all the time (not disabling it). Wasteful on resources but seems more clean than what i'm doing now. I'll post and edit or answer to explain my workaround. – paul Apr 07 '13 at 22:03
  • Paul - thanks for the swift response. I feel that I may simply listen continuously, I dont like it, seeing how often that thing fires, v wasteful, but what to do? thanks – electricSunny Apr 08 '13 at 00:39
  • Old question I know but I'm encountered this recently, so found this post. In your comment to the answer below, you say "I can literally do nothing in `onUpdate` and my widgets are still re-initialized" -- just a thought, do you at least need to call `super.onUpdate()` in your `onUpdate`, even if you do nothing else? Maybe the `super` method will do some stuff that means that your widget won't simply be reset to its initial state? I'm interested in what you are doing now... do you still effectively ignore `onUpdate` because you're using a repeating alarm to trigger the updates? – drmrbrewer Jan 25 '16 at 11:15
  • I don't have a super call, and not sure whether I ever did. Maybe not having it is a problem? But I ended up keeping the broadcast receiver enabled all the time and saving widget state so I could reload it if needed. Basically what I described above. – paul Feb 04 '16 at 03:39

1 Answers1

0

So, if I've understood correctly, there are two distinct things going on:

  1. When network state change notificiation is enabled you are getting extra ACTION_APPWIDGET_UPDATE broadcasts to your AppWidgetProvider.

    Whilst this isn't as one would expect (although I can imagine a coded thinking that widgets would want to update themselves when the network state changes), it isn't outside the defined behaviour of the android system, and so our code needs to be robust to arbitrary ACTION_WIDGET_UPDATE calls. Keeping track of the appWidgetId list and the latest state of each widget on that list is a common way to identify new widgets and immediately required updates, whilst leaving other updating to timer mechanisms.

  2. As you put it: even if the update does nothing the problem still occurs.

    If your onUpdate does nothing, then this means that the re-initialisation has nothing to do with the ACTION_WIDGET_UPDATE. Somewhere, somehow, your code to initialise is being called when you don't expect it to. Now, this is a pain, especially if there's no code reason this should be so. However, I, and others, have experienced this, so I point you two:

When faced with the issue myself, I spent a lot of time putting Log statements in my code to see which parts of my code were called when, and it became clear that the system was restarting my service for no defined reason, but that this was solved as described in those two links. If I had to pick one thing I think was the key, it was running the Service in a separate process to the other activities (including the AppWidgetProvider).

Community
  • 1
  • 1
Neil Townsend
  • 5,784
  • 5
  • 32
  • 50
  • Thanks for the suggestion, but unfortunately this won't work. Part of the problem is that when this update happens the widget is automatically re-initialized to its original state. I can actually ignore the broadcast altogether since I do updates with an alarm manager, but then all the widgets info is reset anyways, I guess by the homescreen. Strange I know... – paul Apr 15 '13 at 00:02
  • Hmmm, I think you may have a design issue then. The `onUpdate` method is precisely that: designed to be called when the widgets need updating, not just initialising. Now, in the actual android implementation, it is rarely called other than at widget initialisation, but it is designed to be used as an update trigger and should be robust to that: the docs [http://developer.android.com/reference/android/appwidget/AppWidgetProvider.html] require it to respond to whenever the system decides the widgets need updating. – Neil Townsend Apr 15 '13 at 08:05
  • Again, I am not doing the initialization. Android, the homescreen, or some bug seems to be causing the re-initialization. I can literally do nothing in `onUpdate` and my widgets are still re-initialized when the seemingly unrelated `setComponentEnabledSetting` is used. This "bug?" only happens on my 4.04 Droid Bionic. Although I have few devices to test with. – paul Apr 15 '13 at 18:04
  • Ahh, now that's facinating, because if you're doing nothing in onUpdate, then the issue isn't with it being called extra times. If your widgets are managed by a service (or other parallel thread), you might like to look at http://stackoverflow.com/questions/15435117/service-being-re-created-by-alarmmanager where I ask a similar question (I noticed the issue because of widgets re-initialising unexpectedly) and in an answer catalogues a collection of things that had helped remove the issue along the way ... – Neil Townsend Apr 15 '13 at 18:07
  • its true that onUpdate being called could be un-related. What I see in the logs is that `ACTION_APPWIDGET_UPDATE` broadcast happens, then onUpdate is called I assume because of that. My service is called once from an alarm manager, which works normally. but even if the service is disabled, i still get the re-initialization. also, there is no reason to get an `ACTION_APPWIDGET_UPDATE` broadcast when network state changes. i assume this is at the root of the problem. – paul Apr 15 '13 at 21:44
  • OK, fair enough. I've tried to clarify the answer to separate the things that I think you're describing ... – Neil Townsend Apr 16 '13 at 08:07