小部件的多个实例仅更新最后一个小部件

Posted

技术标签:

【中文标题】小部件的多个实例仅更新最后一个小部件【英文标题】:Multiple Instances Of Widget Only Updating Last widget 【发布时间】:2011-04-29 23:56:56 【问题描述】:

我有一个 WidgetProvider 和一个 Configure Activity

当 Widget 启动时,它从配置活动开始,我通过对 widgetprovider 进行自定义调用来设置它

(您会注意到来自 sdk 教程示例)

 // Push widget update to surface with newly set prefix
              AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(context);
              AwarenessWidget.updateAppWidget(context, appWidgetManager,
                      mAppWidgetId, position);

            // Make sure we pass back the original appWidgetId
            Intent resultValue = new Intent();
            resultValue.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, mAppWidgetId);
            setResult(RESULT_OK, resultValue);
            finish();

我将小部件 ID 传递给函数....在小部件内部我创建了一个这样的 Intent:

  Intent configIntent = new Intent(context, Configure.class);
    configIntent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId);

    PendingIntent pendingIntent = PendingIntent.getActivity
    (context, 0, configIntent,
    PendingIntent.FLAG_UPDATE_CURRENT);

    views.setOnClickPendingIntent(R.id.MainImage,pendingIntent);

    views.setImageViewResource(R.id.MainImage, lv_images[version]);

    appWidgetManager.updateAppWidget(appWidgetId, views);

我总是引用小部件 ID,甚至将其添加为意图的额外内容 但是当我在主屏幕上获得其中两个小部件时,小部件 ID 始终引用最后放置的小部件 ID

【问题讨论】:

【参考方案1】:

我遇到了类似的问题。只需将其添加到您设置 PendingIntent 的配置活动中:

Uri data = Uri.withAppendedPath(
    Uri.parse(URI_SCHEME + "://widget/id/")
    ,String.valueOf(appWidgetId));
intent.setData(data);

变量 URI_SCHEME 是一个字符串,可以是你想要的任何值。即 - “ABCD” 这会导致每个小部件都有一个唯一的 PendingIntent。

【讨论】:

我没有在配置活动中设置pendingintent,只在活动调用的小部件函数中设置 这行得通,但我不明白为什么。有人可以进一步解释一下这个答案吗? @Mike 经过一番研究,我发现了为什么这个答案有效的解释。请在下面查看我的替代答案。 在我的情况下,我遇到了 Collection 小部件的问题。因此,当我在主屏幕上添加第二个小部件时,RemoteViewFactory 没有调用。因此,我将其粘贴为启动 RemoteViewService 的意图。 intent.data = Uri.parse(intent.toUri(Intent.URI_INTENT_SCHEME)) 工作得很好。【参考方案2】:

这里更深入地解释了为什么您的代码不起作用以及如何修复它。来自 android SDK 文档:

PendingIntent 本身只是对由以下人员维护的令牌的引用 描述用于检索它的原始数据的系统。这 这意味着,即使它拥有的应用程序的进程被杀死, PendingIntent 本身将在其他进程中保持可用 被给予它。如果创建应用程序稍后重新检索相同 一种 PendingIntent(相同的操作,相同的 Intent 操作,数据, 类别、组件和相同的标志),它将收到一个 PendingIntent 表示相同的令牌,如果它仍然有效,并且 因此可以调用 cancel() 来删除它。

由于这种行为,重要的是要知道两个 Intent 何时 出于检索 PendingIntent 的目的,被认为是相同的。 人们常犯的一个错误是创建多个 PendingIntent 具有仅在其“额外”内容上有所不同的意图的对象, 期望每次都能得到不同的 PendingIntent。这不 发生。 Intent 中用于匹配的部分是 Intent.filterEquals 定义的相同。如果你使用两个 Intent 根据 Intent.filterEquals 等效的对象,那么您将 为他们两个获得相同的 PendingIntent。

请注意,指定不同的“额外”内容不足以让 PendingIntents 被认为是唯一的,但使用 setData 设置唯一的 URI 可以。这就是 Snailer 的 URI 解决方案“神奇地”解决问题的原因。

该文档还为该问题提供了不同的(可以说更简单的)解决方案。当您调用 getActivity 时,只需设置一个唯一的 requestCode,而不是创建自定义 URI:

PendingIntent pendingIntent = PendingIntent.getActivity(context, appWidgetId, configIntent, PendingIntent.FLAG_UPDATE_CURRENT);

来源:http://developer.android.com/reference/android/app/PendingIntent.html

【讨论】:

requestCode 当前未被 SDK 使用,但它确实会导致 Intent 被认为是唯一的。文档表明这是对 requestCode 的有效使用:“或提供给 getActivity 的不同请求代码整数”【参考方案3】:

在我的测试中,在 PendingIntent 上使用 setData(...) 并不能解决运行 Android 4.0.4 的 Verizon Thunderbolt 上的问题。它适用于我的其他测试设备和模拟器。

我测试了 requestCode 的使用,它适用于所有情况。我只是将 requestCode 设置为小部件 ID:

pendingIntent = PendingIntent.getService(context, appWidgetId, intent, PendingIntent.FLAG_UPDATE_CURRENT);

【讨论】:

以上是关于小部件的多个实例仅更新最后一个小部件的主要内容,如果未能解决你的问题,请参考以下文章

通过 QStackedWidget 动态修改同一个小部件的多个实例

Flutter:有状态的小部件不更新

为啥我们必须从一个小部件更新多个小部件?

在 Android 中更新多个应用小部件

将 QGraphicsDropShadowEffect 与多个小部件一起使用

创建一个函数来放置子小部件