【问题标题】:Dynamically enabling or disabling a widget does not work动态启用或禁用小部件不起作用
【发布时间】:2010-02-06 13:13:17
【问题描述】:

我们希望通过代码启用或禁用小部件。当我们说 “禁用”是指在应用程序中注册的小部件 不应该出现在用户可用的小部件列表中 他们尝试将小部件添加到他们的主屏幕。 不幸的是,这个问题已经被问过很多次了 回答。

黛安·哈克伯恩(Dianne Hackborn)对另一份单独的 小部件问题表明可以使用 包管理器禁用小部件:

PackageManager pm = context.getPackageManager(); 
pm.setComponentEnabledSetting(new ComponentName("com.example.android.apis", ".appwidget.ExampleBroadcastReceiver"), 
    PackageManager.COMPONENT_ENABLED_STATE_ENABLED, // or DISABLED 
    PackageManager.DONT_KILL_APP); 

但是,这不起作用。小部件组件仍会出现 在小部件列表中。可能是 AppWidgetService(位于 在 Android 源代码的 Base.git 中的 \src\base\services\java\com\android \server),它加载可用小部件的列表,缓存这个列表 可用的小部件。但是,如果是这样的话,那么上面 启用或禁用小部件组件的代码将在 设备重置,因为没有缓存;它不是。

我也尝试过覆盖一些方法 AppWidgetProvider,例如过滤掉任何事件。我不认为 这将去任何地方,因为填充了 AppWidgetService 列表,使用包管理器查找所有捕获的组件 启动时的 ACTION_APPWIDGET_UPDATE 动作和一个包是 添加(即安装了新应用程序)。提供者的唯一时间是 从此列表中删除是在 ACTION_PACKAGE_REMOVED 广播中。 因此,鉴于提供者将始终存在,无论 组件的启用/禁用状态,我已经查看了实际 列出当用户长时从 Launcher 应用程序显示的活动 点击桌面并添加一个小部件:AppWidgetPickActivity in 设置.GIT 中 com.android.settings。不幸的是,这填充了列表 直接来自 AppWidgetService,没有任何过滤 组件的启用状态: 无效 putInstalledAppWidgets(列表项){ 已安装列表 = mAppWidgetManager.getInstalledProviders(); putAppWidgetItems(已安装,空,项目); }

我很想看看是否有人克服了这个障碍。也许我是 以错误的方式去做。我想要的只是能够删除一个 用户尝试使用时可用的小部件列表中的小部件 将小部件添加到他们的主屏幕。

【问题讨论】:

  • 3年后有这个问题的更新吗?

标签: android widget


【解决方案1】:

可能是 AppWidgetService (位于 Android 源的 Base.git 在 \src\base\services\java\com\android \server),它加载的列表 可用的小部件,缓存此列表 可用的小部件。

确实如此,据我所知。它将列表存储在mInstalledProviders;此列表是通过readStateFromFileLocked() 添加到的,似乎是从系统启动逻辑调用的。

如果是这样的话,那么 上面的代码启用或 禁用小部件组件将 设备重置后工作,因为 不会有缓存;它没有。

您假设一个 RAM 缓存。缓存是一个 XML 文件。

不幸的是,这填充了 直接从列表中 AppWidgetService,没有任何 过滤组件的启用 状态

这似乎是 Android 中的一个错误。更一般地说,我认为整个缓存都是错误——如果缓存不同步,我认为没有办法恢复。

如果您还没有这样做,我建议您将您的文章作为问题发布到 public Android issue tracker

【讨论】:

    【解决方案2】:

    它对我有用!我必须使用 DONT_KILL_APP 否则它会立即杀死我的应用程序。另外,我必须注释掉条件以检查它是否已经处于相同状态。

    这是我创建的辅助方法:

    public void setMyCustomWidgetEnabled( boolean bEnable )
        {
            Log.d( LOG_TAG_NAME, "Entering setMyCustomWidgetEnabled( " + bEnable + " )..." );
    
            PackageManager rPackageManager = getPackageManager();
            if( rPackageManager != null )
            {
                ComponentName rComponentName = new ComponentName( getBaseContext(), MyCustomWidget.class );
    
                int nComponentEnabledState = rPackageManager.getComponentEnabledSetting( rComponentName );
    
                if( bEnable )
                {
                    //if( nComponentEnabledState == PackageManager.COMPONENT_ENABLED_STATE_DISABLED )
                    {
                        // Change the State to Enabled
                        rPackageManager.setComponentEnabledSetting( rComponentName, PackageManager.COMPONENT_ENABLED_STATE_ENABLED, PackageManager.DONT_KILL_APP );
    
                        Log.d( LOG_TAG_NAME, "-> Changed My Custom Widget' to ENABLED!" );
                    }
                }
                else
                {
                    //if( nComponentEnabledState == PackageManager.COMPONENT_ENABLED_STATE_ENABLED )
                    {
                        // Change the State to Disabled
                        rPackageManager.setComponentEnabledSetting( rComponentName, PackageManager.COMPONENT_ENABLED_STATE_DISABLED, PackageManager.DONT_KILL_APP );
    
                        Log.d( LOG_TAG_NAME, "-> Changed 'My Custom Widget' to DISABLED!" );
                    }
                }
            }
    
            Log.d( LOG_TAG_NAME, "Leaving setMyCustomWidgetEnabled( " + bEnable + " )..." );
    }
    

    【讨论】:

    • 看起来启用/禁用仅在清单中的接收器最初启用时才有效。如果它被清单禁用,则以编程方式启用/禁用将不起作用。请问您能确认一下这种行为吗?
    • @peter.bartos 是的,它仅在最初在清单中启用时才有效。同样对于应用程序禁用小部件,用户需要强制退出应用程序以“更新”小部件列表,如果它没有以编程方式杀死它。
    【解决方案3】:

    特点

    pm.setComponentEnabledSetting()
    

    在 ICS 中工作。当小部件被禁用时,它会从可用小部件列表中删除。暂时的小小的安慰,但至少已经得到纠正。

    【讨论】:

    • 只要widget Provider接收器默认没有被禁用就可以工作
    【解决方案4】:

    platform code 中有一个错误导致系统忽略清单中禁用的小部件。 此问题已针对 Android 12 进行修复,但仍会影响以前的版本。

    您的小部件提供者的接收器必须在清单中启用,否则它将永远不会显示给用户。

    <!-- DO NOT set android:enabled="false" on this receiver! -->
    <receiver android:name="ExampleAppWidgetProvider" >
    <intent-filter>
        <action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
    </intent-filter>
    <meta-data android:name="android.appwidget.provider"
               android:resource="@xml/example_appwidget_info" />
    

    只要小部件默认启用,PackageManager.setComponentEnabledSetting 将在以后禁用并重新启用它。

    您可以为MY_PACKAGE_REPLACED 注册一个接收器,以便在更新您的应用时立即为用户禁用此功能。要处理全新安装,您需要在应用的其他位置添加代码,以在应用首次运行时禁用小部件。

    【讨论】:

      猜你喜欢
      • 2017-08-05
      • 1970-01-01
      • 1970-01-01
      • 2014-03-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多