【问题标题】:Enabling/disableing receiver (CONNECTIVITY_CHANGE) causes APPWIDGET_UPDATE broadcast启用/禁用接收器 (CONNECTIVITY_CHANGE) 会导致 APPWIDGET UPDATE 广播
【发布时间】:2013-01-30 21:37:35
【问题描述】:

我有一个接收器正在监听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,然后再次来自 @ 987654325@广播)。

另外,这似乎只发生在我的 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 还将我的小部件重置为其初始状态,就像它第一次添加到主屏幕一样。在我有连接的情况下,我可以进行双重更新,因为所有信息都可以重新填充。我还必须自己进行更新,因为该错误似乎是特定于设备的,而未受影响的设备仍需要更新。

如果我没有连接,我会从之前保存的状态恢复小部件。这意味着每次我成功更新时,我都会将所有内容保存到 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()
}

【问题讨论】:

  • 保罗 - 我也有同样的问题。它让我发疯!.....
  • 我还没有找到好的解决方案。我现在正在通过保存额外的状态来解决它。如果您发现了什么,请发布!我看到了这个bug report,它是不同的,但可能是相关的。
  • 保罗 - 我仍然没有进一步前进。我很想听听你的解决方法,节省额外的状态。你介意分享一下吗? ta
  • Funkatron - 我实际上可能会切换回让 NetworkStateReceiver 一直在监听(而不是禁用它)。浪费资源,但似乎比我现在做的更干净。我将发布并编辑或回答以解释我的解决方法。
  • 保罗 - 感谢您的快速响应。我觉得我可能只是不停地听,我不喜欢它,看到那个东西多久触发一次,很浪费,但是该怎么办?谢谢

标签: android broadcastreceiver android-appwidget


【解决方案1】:

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

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

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

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

    如果您的onUpdate 什么都不做,那么这意味着重新初始化与ACTION_WIDGET_UPDATE 无关。不知何故,当您不希望它调用时,您的初始化代码会被调用。现在,这很痛苦,特别是如果没有代码原因应该如此。但是,我和其他人都经历过这种情况,所以我指出你们两个:

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

【讨论】:

  • 感谢您的建议,但很遗憾这不起作用。部分问题在于,当此更新发生时,小部件会自动重新初始化为其原始状态。实际上,我可以完全忽略广播,因为我使用警报管理器进行了更新,但是无论如何,所有小部件信息都会被重置,我猜是在主屏幕上。奇怪我知道...
  • 嗯,我想你可能有一个设计问题。 onUpdate 方法正是这样:设计为在小部件需要更新时调用,而不仅仅是初始化。现在,在实际的 android 实现中,除了在小部件初始化时很少调用它,但它被设计为用作更新触发器并且应该对此具有鲁棒性:文档 [developer.android.com/reference/android/appwidget/… 要求它在系统时响应决定小部件需要更新。
  • 再一次,我没有进行初始化。 Android、主屏幕或某些错误似乎导致重新初始化。我在onUpdate 中实际上什么都做不了,当使用看似不相关的setComponentEnabledSetting 时,我的小部件仍会重新初始化。这个“虫子”?只发生在我的 4.04 Droid Bionic 上。虽然我可以测试的设备很少。
  • 啊,现在这很有趣,因为如果您在 onUpdate 中什么都不做,那么问题不在于它被额外调用。如果您的小部件由服务(或其他并行线程)管理,您可能想查看stackoverflow.com/questions/15435117/… 我问了一个类似的问题(我注意到这个问题是因为小部件意外重新初始化)并在答案中对集合进行了分类在此过程中帮助解决问题的事情......
  • 确实 onUpdate 被调用可能是不相关的。我在日志中看到的是 ACTION_APPWIDGET_UPDATE 广播发生了,然后我假设调用 onUpdate 。我的服务从正常工作的警报管理器调用一次。但即使该服务被禁用,我仍然会重新初始化。此外,当网络状态发生变化时,没有理由获得ACTION_APPWIDGET_UPDATE 广播。我认为这是问题的根源。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多