启用/禁用接收器(CONNECTIVITY_CHANGE)会导致APPWIDGET_UPDATE广播

时间:2013-01-30 21:37:36

标签: android broadcastreceiver android-appwidget

我有一个接收器正在监听android.net.conn.CONNECTIVITY_CHANGE,这样我就可以在恢复连接时更新我的​​appwidget。这很好用,除非我通过以下方式启用或禁用我的接收器时会遇到一些奇怪的行为:

ComponentName receiver = new ComponentName(this, NetworkStateReceiver.class);
PackageManager pm = getPackageManager();
pm.setComponentEnabledSetting(receiver, PackageManager.COMPONENT_ENABLED_STATE_ENABLED,
        PackageManager.DONT_KILL_APP);

当状态发生变化时,我还会收到一个android.appwidget.action.APPWIDGET_UPDATE广播到我的appwidget的接收器,导致我的appwidget在检测到连接丢失后再次更新,然后在返回连接时再次更新(一次故意来自我的NetworkStateReceiver,然后再来自APPWIDGET_UPDATE广播)。

此外,这似乎只发生在我的4.04设备上而不是我的2.1设备上。

NetworkStateReceiver和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>

我尝试了几种方法来解决这个问题,但没有一种方法可以解决这个问题。

我可以忽略来自APPWIDGET_UPDATE广播的任何更新。实际上我已经这样做了,因为我的所有appwidget更新都是在首次创建时通过警报管理器或配置活动通过服务进行的。由于某些原因(并且可能表明发生了什么),APPWIDGET_UPDATE广播也会导致我的远程视图恢复到其第一次添加的XML状态。我可以通过保存额外的状态来解决这个问题,其中包括位图。不理想。

我可以让NetworkStateReceiver一直监听而不是启用/禁用,但这违反了Android的建议,并且有充分的理由,因为这意味着不必要的广播。

其他想法?

编辑:对我当前解决方法的进一步说明。

即使我使用闹钟触发我的更新,我也无法忽略APPWIDGET_UPDATE广播。这是因为APPWIDGET_UPDATE还将我的窗口小部件重置为其初始状态,就像它第一次添加到主屏幕一样。在我有连接的情况下,我可以进行双重更新,因为可以重新填充所有信息。我还需要自己做更新,因为这个bug似乎是设备特定的,不受影响的设备仍然需要更新。

如果我没有连接,我会从之前保存的状态恢复窗口小部件。这意味着每次成功更新时,我都会将所有内容保存到SharedPreferences,以便在互联网无法正常重新填充数据时,可以在其中一个“强制更新”中恢复。

在我的AppWidgetProvider我做(简化):

Intent intent = new Intent(context, WidgetUpdateService.class);
intent.putExtra("loadFromSaved", true);   // this will be false when coming from AlarmManager
context.startService(intent);

WidgetUpdateService.onStartCommand()(也简化):

if (intent.getExtras().getBoolean("loadFromSaved") {
    widgetLoader.loadFromSavedData();
} else {
    widgetLoader.load()
}

1 个答案:

答案 0 :(得分:0)

所以,如果我理解正确,有两个不同的事情发生:

  1. 启用网络状态更改通知后,您将ACTION_APPWIDGET_UPDATE收到额外AppWidgetProvider次广播。

    虽然这并不像人们期望的那样(虽然我可以想象一个编码思维,即当网络状态发生变化时小部件会想要自己更新),但它并不在android系统的定义行为之外,所以我们的代码需要对任意ACTION_WIDGET_UPDATE调用具有鲁棒性。跟踪appWidgetId列表以及该列表上每个小部件的最新状态是识别新小部件和立即需要更新的常用方法,同时将其他更新留给计时器机制。

  2. 正如您所说:即使更新什么也不做,问题仍然存在。

    如果您的onUpdate什么都不做,那么这意味着重新初始化与ACTION_WIDGET_UPDATE无关。在某个地方,不知何故,当你不期望它时,你的代码被初始化。现在,这是一个痛苦,特别是如果没有代码原因这应该是这样。但是,我和其他人都经历过这一点,所以我指出两点:

  3. 当我自己面对这个问题时,我花了很多时间将Log语句放在我的代码中,以查看我的代码的哪些部分被调用,并且很明显系统正在重新启动我的服务,但没有明确的原因,但是这是按照这两个链接中的描述解决的。如果我必须选择一个我认为是关键的东西,那就是在与其他活动(包括AppWidgetProvider)分开的过程中运行服务。