【问题标题】:Widget not deleted when passing RESULT_CANCELED as result for configuration activity将 RESULT_CANCELED 作为配置活动的结果时未删除小部件
【发布时间】:2023-04-02 08:40:01
【问题描述】:

我的小部件有一些问题。这是描述:

上下文:

我有一个家庭小部件。

当我添加它时,它会弹出一个配置活动,用于为小部件设置一些参数。

如果我在完成配置Activity之前调用setResult(RESULT_OK, resultValue);,小部件就会被添加到Home中。

如果我通过将小部件拖到垃圾箱来删除它,则会调用我的 AppWidgetProvider 类中的 public void onDeleted(Context context, int[] appWidgetIds)。 到目前为止一切顺利。

问题: 如果配置 Activity 以结果代码 RESULT_CANCELED (setResult(RESULT_CANCELED);) 退出,则不会调用我的 AppWidgetProvider 类中的 public void onDeleted(Context context, int[] appWidgetIds)并且小部件保留在活动小部件列表中。当我重新启动手机时,我的 AppWidgetProvider 类中的 onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) 被调用,并且在 int[] appWidgetIds 我拥有所有应该是的小部件(ID)取消(添加前已删除)+ 活动的(实际显示在主页上的)。通过拖拽到垃圾箱中删除的 Widget 不会显示在此列表中。随着时间的推移,如果用户从配置活动中取消,这个小部件 ID 列表会越来越大。

API 参考说明如下: "如果你使用Activity.setResult()返回RESULT_OK,就会添加AppWidget,你会收到一个针对这个AppWidget的ACTION_APPWIDGET_UPDATE广播。如果你返回RESULT_CANCELED,主机会取消添加,不显示这个AppWidget,你会收到ACTION_APPWIDGET_DELETED 广播。”

谁能给我一些提示? 谢谢。

这是我的清单:

<application android:icon="@drawable/icon" android:label="@string/app_name" android:debuggable="true">
    <receiver android:name=".MytWidget" android:label="@string/app_name">
        <intent-filter>
            <action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
        </intent-filter>
        <meta-data android:name="android.appwidget.provider"
                    android:resource="@xml/my_widget_provider" />
    </receiver>
    <activity android:name=".ConfigurationActivity">
        <intent-filter>
            <action android:name="android.appwidget.action.APPWIDGET_CONFIGURE" />
        </intent-filter>
    </activity>
</application>

其余代码不相关,因为上面已经解释过了(我无权发布它)。

【问题讨论】:

标签: android android-widget


【解决方案1】:

我遇到了同样的问题,我是在 onPause 事件中这样做的

public void removeWidget(int appWidgetId) {
    AppWidgetHost host = new AppWidgetHost(Config.this, 1);
    host.deleteAppWidgetId(appWidgetId);
}

检查了小部件 ID,小部件已被删除。 如果您只有一个应用小部件主机,则主机 ID 并不重要。

private boolean canceled = true;

@Override
protected void onPause() {
    if(canceled) {
        removeWidget(appWidgetId);
    }
    super.onPause();
}

在确定点击中,我将canceled设置为false

【讨论】:

  • +1 不错的第一个答案。将来,您可以在代码片段中显示更多上下文(例如,显示 onPause() 方法声明而不是写“onPause 事件”)。
  • 为什么在 onPause 事件中?您如何知道哪些 Id 是幽灵,从而知道要删除哪些 Id?
  • 确实不错的解决方案,但是当主屏幕上没有小部件的空间时它会失败。
  • 很好的解决方案,但我有同样的问题:“为什么在 onPause 事件中?”如果您关闭屏幕然后再打开,onPause() 将删除小部件。我在 'onDestroy()' 处添加了 removeWidget(appWidgetId) 效果很好。
  • 不错的尝试,但这是行不通的。当您对配置活动执行配置更改时,onPauseonDestroy 都会被调用。例如,旋转您的设备...
【解决方案2】:

您确定您的代码不相关吗?您清单中的所有内容都超出了书本,并且看起来不错。您的代码应该与此非常相似:

    public void configCancelOnClick(View v) {
    MyLog.d(TAG, "configCancelOnClick");
    Intent intent = new Intent();
    intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId);
    setResult(RESULT_CANCELED, intent);
    finish();
}

需要 putExtra 来告诉操作系统您没有创建哪个小部件... 需要完成才能正确关闭。如果没有它,您将无法将意图正确传递给操作系统并丢失 setResult。

最后,当配置没有正确退出(返回键、主页键或错误代码)时,会创建一个幽灵小部件。即使使用完美的代码,如果用户在配置中点击主页键,您将有一个小部件排队到系统中,而该小部件实际上并不存在于任何主屏幕上。这就是为什么我称他们为鬼。一旦小部件成功完成配置,它将在从主屏幕删除时调用 onDeleted。剩下的问题是,如果创建了 ghost,onDisabled 将永远不会运行。

最后一次检查。由于配置运行,您的 info xml 文件中有以下内容。但以防万一,它看起来像这样:

    android:configure=your.package.name.ConfigurationActivity"

【讨论】:

  • 这是一个,真正正确的答案 :) 不需要 sharedPreferences 混乱,我所需要的只是在 Intent 中传递 appWidgetId。谢谢!
  • 优秀的答案!今天尝试学习AppWidgetHost & AppWidget,偶然发现了这个教程:leonardofischer.com/… - 可能这个bug不在Google SDK中,可能是在3-rd Party Launcher里面自定义的AppWidgetHost:开发者可能忘记删除了AppWidget,它只是“取消”(用户按回配置活动)。请参阅上面教程中的“配置小部件”段落
  • 这不是解决方案,也没有记录,这就是它所说的取消配置:当您的配置活动首次打开时,将活动结果设置为 RESULT_CANCELED。这样,如果用户在到达结束前退出Activity,就会通知App Widget宿主取消配置,不会添加App Widget,这里:developer.android.com/guide/topics/appwidgets/index.html
【解决方案3】:

我这样解决了这个问题,

在小部件提供程序的 onUpdate() 方法中,我检查小部件是否已配置,如果不是,我什么也不做,所以没有幽灵小部件。在配置结束时,我将其设置为 true,然后就可以开始了。只是不要忘记在删除小部件时将其从 sharedpreference 中删除。

@Override
public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds)
{
    super.onUpdate(context, appWidgetManager, appWidgetIds);

    for(final int appWidgetId : appWidgetIds)
    {
        final StringBuilder stringBuilder = new StringBuilder();
        stringBuilder.append(appWidgetId);
        stringBuilder.append("_conf");
        if(context.getSharedPreferences("settings",0).getBoolean(stringBuilder.toString(),false)) 
            updateAppWidget(context,appWidgetId,appWidgetManager);

    }


}

【讨论】:

    【解决方案4】:

    自古以来,小部件似乎存在许多问题。也就是说,在寻找其中一个的解决方案时,我偶然发现了这篇文章:https://code.google.com/p/android/issues/detail?id=2539#c15

    基本上这个想法是从清单中删除应用程序配置活动,并在 onUpdate 期间检查小部件是否已配置,如果没有打开配置活动。

    它对用户完全透明,据说可以解决“添加/僵尸小部件”问题。现在就试试。


    但它并没有解决已移除的小部件在重新启动时更新的问题,即使它似乎已在最近的 Android 版本中得到修复(4.4+ 不确定是哪一个?)。

    在旧版本的 Android 上,我观察到我从启动器中手动删除的所有小部件在重新启动时都会变成僵尸,操作系统有效地为每个小部件调用 onUpdate,因此我必须保留已删除小部件的列表。

    现在已删除的小部件 ID 实际上被重新用于新的小部件,因此我必须停止跟踪已删除的小部件。遗憾的是,我不知道什么时候(哪个 Android 版本)这个问题得到了修复,并且 ID 开始被重新使用。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-07-11
      • 1970-01-01
      • 2013-07-02
      • 1970-01-01
      • 2012-07-29
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多