Android:如何强制更新特定类型的所有小部件

时间:2011-11-29 00:43:35

标签: android widget

我在这些方面看到了很多问题,而且我一遍又一遍地看到同样的答案。我不想为我的应用程序所拥有的每种小部件都提供服务,特别是因为我的应用程序已经拥有2个持久性服务。

具体来说,如果我的一个现有服务发现数据已更改,我想更新我的小部件。在计时器上执行此操作很烦人,因为它可能是更新之间的天数,也可能在一小时内有几天。我希望我的小部件始终显示最新信息。

Android小部件设计似乎是基于您的小部件在需要时提取信息的基础上工作,我认为有很多明智的场景,活动可能希望将数据推送到小部件。

阅读下面的答案,了解我如何确切地解决这个问题。据我所知,如果做得好,没有任何不利影响。

3 个答案:

答案 0 :(得分:37)

要强制更新特定窗口小部件提供程序的窗口小部件,我们需要执行以下操作:

  • 设置我们的提供商以接收专门的广播
  • 发送专业广播:
    1. 与提供商关联的所有当前窗口小部件ID
    2. 要发送的数据
    3. 只有我们的提供商回复的密钥(重要!)
  • 让我们的小部件更新点击(没有服务!)

第1步 - 设置我们的AppWidgetProvider

我不会详细介绍如何创建info xml文件或更改Android Manifest - 如果你不知道如何正确创建一个小部件,那么你应该先阅读很多教程。< / p>

以下是一个示例AppWidgetProvider类:

public class MyWidgetProvider extends AppWidgetProvider {

public static final String WIDGET_IDS_KEY ="mywidgetproviderwidgetids";
public static final String WIDGET_DATA_KEY ="mywidgetproviderwidgetdata";

}

@Override
public void onReceive(Context context, Intent intent) {
    if (intent.hasExtra(WIDGET_IDS_KEY)) {
        int[] ids = intent.getExtras().getIntArray(WIDGET_IDS_KEY);
        if (intent.hasExtra(WIDGET_DATA_KEY)) {
           Object data = intent.getExtras().getParcelable(WIDGET_DATA_KEY);
           this.update(context, AppWidgetManager.getInstance(context), ids, data);
        } else {
            this.onUpdate(context, AppWidgetManager.getInstance(context), ids);
        }
    } else super.onReceive(context, intent);
}

@Override
public void onUpdate(Context context, AppWidgetManager appWidgetManager,
        int[] appWidgetIds) {
    update(context, appWidgetManager, appWidgetIds, null);
}

//This is where we do the actual updating
public void update(Context context, AppWidgetmanager manager, int[] ids, Object data) {

    //data will contain some predetermined data, but it may be null
   for (int widgetId : ids) {
        .
        .
        //Update Widget here
        .
        .
        manager.updateAppWidget(widgetId, remoteViews);
    }
}

第2步 - 发送广播

在这里,我们可以创建一个静态方法,让我们的小部件更新。重要的是我们使用自己的键和小部件更新操作,如果我们使用AppWidgetmanager.EXTRA_WIDGET_IDS,我们不仅会破坏我们自己的小部件,还会破坏其他小部件。

public static void updateMyWidgets(Context context, Parcelable data) {
    AppWidgetManager man = AppWidgetManager.getInstance(context);
    int[] ids = man.getAppWidgetIds(
            new ComponentName(context,MyWidgetProvider.class));
    Intent updateIntent = new Intent();
    updateIntent.setAction(AppWidgetManager.ACTION_APPWIDGET_UPDATE);
    updateIntent.putExtra(MyWidgetProvider.WIDGET_ID_KEY, ids);
    updateIntent.putExtra(MyWidgetProvider.WIDGET_DATA_KEY, data);
    context.sendBroadcast(updateIntent);
}

如果对多个提供商使用此方法,请确保使用不同的密钥。否则你可能会发现widget a的代码更新小部件b,这可能会产生一些奇怪的后果。

第3步 - 点击

进行更新

另一件好事是让我们的小部件在点击时进行恶意更新。将以下代码添加到update方法中以实现此目的:

RemoteViews views = 
      new RemoteViews(context.getPackageName(),R.layout.mywidget_layout);

Intent updateIntent = new Intent();
updateIntent.setAction(AppWidgetManager.ACTION_APPWIDGET_UPDATE);
updateIntent.putExtra(myWidgetProvider.WIDGET_IDS_KEY, ids);
PendingIntent pendingIntent = PendingIntent.getBroadcast(
      context, 0, updateIntent, PendingIntent.FLAG_UPDATE_CURRENT);

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

此代码将导致在单击窗口小部件时调用onUpdate方法。

备注

  • 对updateWidgets()的任何调用都将导致更新我们窗口小部件的所有实例。
  • 单击小部件将导致我们小部件的所有实例都更新
  • 无需维修
  • 当然,请注意不要经常更新 - 小部件更新会使用电池电量。
  • 请记住,所有窗口小部件提供程序都会收到广播,并且我们的特殊键会确保它只是我们实际更新的窗口小部件。

答案 1 :(得分:4)

很抱歉OP有一个迟到的答案,但对于其他任何人,你可以使用这样的方法来更新特定类型的所有app小部件(布局和类):

public static void updateAllWidgets(final Context context,
                                    final int layoutResourceId,
                                    final Class< ? extends AppWidgetProvider> appWidgetClass)
{
    RemoteViews remoteViews = new RemoteViews(context.getPackageName(), layoutResourceId);

    AppWidgetManager manager = AppWidgetManager.getInstance(context);
    final int[] appWidgetIds = manager.getAppWidgetIds(new ComponentName(context, appWidgetClass));

    for (int i = 0; i < appWidgetIds.length; ++i)
    {
        manager.updateAppWidget(appWidgetIds[i], remoteViews);
    }
}

这样做会为您的布局创建一个RemoteViews然后获取AppWidgetManager并查找您提供的类的所有应用小部件,迭代它们并更新它们。

答案 2 :(得分:-3)

每当你处理类型时,只需简单地处理静态就可以了。并且,如果您希望基于“触发器”发生特定事情,我总是建议基于事件的编程... Intent本质上是Android中的默认“事件”(用于在事件中传递数据,确保对象实现Parcelable接口)。

在各种论坛和SDK文档中有很多这些概念的例子。