我正在创建一个测试小部件,通过单击其按钮显示随机数。一切都在我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));
}
}
}
答案 0 :(得分:1)
在BroadcastReceiver
中动态注册AppWidgetProvider
是一个不稳定的解决方案。 AppWidgetProvider
本身是BroadcastReceiver
,在应用清单中静态注册的实例意味着相当短暂。
但是,由于AppWidgetProvider
是BroadcastReceiver
,我们可以利用这一点,只需在点击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