重新启动后,按钮单击时,小组件onUpdate未设置pendingIntent

时间:2018-02-27 22:03:22

标签: android widget broadcastreceiver android-pendingintent

我正在创建一个测试小部件,通过单击其按钮显示随机数。一切都在我onUpdate的{​​{1}}内独立,包括Provider。它工作正常,但重新启动手机后pendingIntent无效,虽然views.setOnClickPendingIntent重新创建没有问题,但按钮无响应。

RemoteViews

清单:

public class TestWidget extends AppWidgetProvider {
    static HashMap<Integer, BroadcastReceiver> br = new HashMap<>();

    static void updateAppWidget(Context context, final AppWidgetManager appWidgetManager,
                                final int appWidgetId) {
        context = context.getApplicationContext();
        final RemoteViews views = new RemoteViews(context.getPackageName(), R.layout.test_widget);

        BroadcastReceiver broadcastReceiver = new BroadcastReceiver() {
            @Override
            public void onReceive(Context context, Intent intent) {
                views.setTextViewText(R.id.appwidget_text, Math.random() + "");
                appWidgetManager.updateAppWidget(appWidgetId, views);
            }
        };
        br.put(appWidgetId, broadcastReceiver);//to unregister later

        Intent intent = new Intent("action");
        IntentFilter intentFilter = new IntentFilter("action");

        context.registerReceiver(broadcastReceiver, intentFilter);
        PendingIntent pendingIntent = PendingIntent.getBroadcast(context, 123, intent, PendingIntent.FLAG_UPDATE_CURRENT);
        views.setOnClickPendingIntent(R.id.appwidget_button, pendingIntent);

        appWidgetManager.updateAppWidget(appWidgetId, views);
    }

    @Override
    public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) {
        for (int appWidgetId : appWidgetIds) {
            updateAppWidget(context, appWidgetManager, appWidgetId);
        }
    }

    @Override
    public void onDeleted(Context context, int[] appWidgetIds) {
        for (int appWidgetId : appWidgetIds) {
            context.unregisterReceiver(br.get(appWidgetId));
        }
    }
}

2 个答案:

答案 0 :(得分:1)

BroadcastReceiver中动态注册AppWidgetProvider是一个不稳定的解决方案。 AppWidgetProvider本身是BroadcastReceiver,在应用清单中静态注册的实例意味着相当短暂。

但是,由于AppWidgetProviderBroadcastReceiver,我们可以利用这一点,只需在点击TestWidget中定位PendingIntent即可。我们还可以在此处将Widget ID作为额外添加到Intent,因此我们会在点击触发时更新正确的ID。例如:

Intent intent = new Intent(context, TestWidget.class);
intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId);
PendingIntent pendingIntent = PendingIntent.getBroadcast(context,
                                                         appWidgetId,
                                                         intent,
                                                         PendingIntent.FLAG_UPDATE_CURRENT);
views.setOnClickPendingIntent(R.id.appwidget_button, pendingIntent);

请注意,我们还为appWidgetId的{​​{1}}使用PendingIntent。为每个Widget实例使用不同的requestCode非常重要,以免错误的Widget实例使用错误的附加内容进行更新。使用已经独特的Widget ID可以让我们轻松完成。

然后我们覆盖PendingIntent的{​​{1}}方法,并检查TestWidget的操作,以确定这是我们的点击广播,还是从系统广播的普通Widget事件。在上面的示例中,我们没有设置操作,因此我们只需在此处检查null。但是,您当然可以指定一个操作onReceive(),在某些情况下最好这样做;例如,如果你的Widget中有多个Intent,并且需要区分他们的点击广播。

String

在上面,您可以看到我们将广播传递给Button方法,如果我们发现它不是我们的。然后,@Override public void onReceive(Context context, Intent intent) { if (intent.getAction() == null) { int appWidgetId = intent.getIntExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, -1); if (appWidgetId != -1) { updateWidgetText(context, appWidgetId, Math.random() + ""); } } else { super.onReceive(context, intent); } } 的{​​{1}}会检查super,并按照惯例委托给相应的事件方法。

除了是一个稳定的解决方案之外,这种方法还有另一个结果,即不需要为每个Widget实例创建,注册和注销单独的AppWidgetProvider实例。虽然我们添加了onReceive()方法,但我们可以删除所有动态Intent代码,因此我们的BroadcastReceiver类仍然非常简短。

onReceive()

答案 1 :(得分:0)

如果有人遇到类似问题,这是上述测试项目的完整结果。 在配置页面中动态添加多个按钮,每个按钮都具有用户定义的行为。 https://github.com/Alireza-Jamali/daily-task-checker