更新小部件列表视图

Updating Widget Listview

在我的小部件中,我有一个刷新按钮,用于告诉(自定义)列表视图数据集已更改。现在,单击刷新按钮时会调用我的 onRecieve 回调,但传递的意图包为空,因此我无法对 ID 调用 onUpdate。

我检查了添加额外功能的函数,它说它添加的整数数组长度为 1 且非空,我不确定为什么这不起作用:/希望这里有人可以给我一只手。

谢谢。

WidgetProvider.java

public class WidgetProvider extends AppWidgetProvider {

    @Override
    public void onDeleted(Context context, int[] appWidgetIds)
    {
        super.onDeleted(context, appWidgetIds);
    }

    @Override
    public void onDisabled(Context context)
    {
        super.onDisabled(context);
    }

    @Override
    public void onEnabled(Context context)
    {
        super.onEnabled(context);
    }

    @Override
    public void onReceive(Context context, Intent intent)
    {
        System.out.println("RECIEVED SOMETHING:" + intent.getAction());
        AppWidgetManager appWidgetMgr = AppWidgetManager.getInstance(context);

        Bundle extras = intent.getExtras();
        int[] ids = extras.getIntArray(AppWidgetManager.EXTRA_APPWIDGET_IDS); //NPE ON THIS LINE, EXTRAS IS NULL

        System.out.println("SENDING AN UPDATE");
        onUpdate(context, appWidgetMgr, ids);

        super.onReceive(context, intent);
    }

    protected PendingIntent getPendingSelfIntent(Context context, String action, int[] ids) {
        Intent intent = new Intent(context, getClass());
        intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS, ids);
        System.out.println("PUTTING ARRAY OF LEN: " + ids.length);
        intent.setAction(action);
        return PendingIntent.getBroadcast(context, 0, intent, 0);
    }

    @Override
    public void onUpdate(Context context, AppWidgetManager appWidgetManager,
                         int[] appWidgetIds)
    {
        for(int i=0;i<appWidgetIds.length;i++)
        {
            System.out.println("CHECK");
            RemoteViews rv = new RemoteViews(context.getPackageName(),
                    R.layout.app_widget);

            Intent intent = new Intent(context, WidgetService.class);
            intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID,
                    appWidgetIds[i]);
            intent.setData(Uri.parse(intent.toUri(Intent.URI_INTENT_SCHEME)));

            rv.setRemoteAdapter(R.id.list, intent);

            rv.setOnClickPendingIntent(R.id.refresh, getPendingSelfIntent(context,
                    "refresh", appWidgetIds));

            appWidgetManager.updateAppWidget(appWidgetIds[i], rv);
        }
        super.onUpdate(context, appWidgetManager, appWidgetIds);
    }
}

编辑:新的 onRecieve 函数,同样的错误:

    @Override
    public void onReceive(Context context, Intent intent)
    {
        if("refresh".equals(intent.getAction())) {
            System.out.println("RECIEVED SOMETHING:" + intent.getAction());
            AppWidgetManager appWidgetMgr = AppWidgetManager.getInstance(context);

            Bundle extras = intent.getExtras();

            int[] ids = extras.getIntArray(AppWidgetManager.EXTRA_APPWIDGET_IDS);

            System.out.println("SENDING AN UPDATE");
            onUpdate(context, appWidgetMgr, ids);
        }

        super.onReceive(context, intent);
    }

如果您查看 source for AppWidgetProvider,每个标准小部件操作都会首先调用 onReceive(),而不仅仅是您的自定义代码。您应该将代码包装在 if 检查中,以确保按下的是您的按钮。

// In onReceive()
if ("refresh".equals(intent.getAction())) {
  // Do your code
}

您还会从 PendingIntent documentation 中注意到:

Because of this behavior, it is important to know when two Intents are considered to be the same for purposes of retrieving a PendingIntent. A common mistake people make is to create multiple PendingIntent objects with Intents that only vary in their "extra" contents, expecting to get a different PendingIntent each time. This does not happen. The parts of the Intent that are used for matching are the same ones defined by Intent.filterEquals. If you use two Intent objects that are equivalent as per Intent.filterEquals, then you will get the same PendingIntent for both of them.

...

If you only need one PendingIntent active at a time for any of the Intents you will use, then you can alternatively use the flags FLAG_CANCEL_CURRENT or FLAG_UPDATE_CURRENT to either cancel or modify whatever current PendingIntent is associated with the Intent you are supplying.

因此您还应该将对 PendingIntent.getBroadcast() 的调用更新为

return PendingIntent.getBroadcast(context, 0, intent,
  PendingIntent.FLAG_UPDATE_CURRENT);

当然,另一种方法是只调用 AppWidgetManager#getAppWidgetIds() 并完全跳过任何额外设置。