发送多种意图的小部件
Posted
技术标签:
【中文标题】发送多种意图的小部件【英文标题】:Widget sending multiple types of intents 【发布时间】:2013-06-13 22:37:38 【问题描述】:我正在构建一个具有多个按钮的小部件,每个按钮都将自己的意图发送到广播接收器。广播接收器应该根据按下的按钮显示 Toast 消息。目前的代码如下所示:
public class WidgetProvider extends AppWidgetProvider
@Override
public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds)
ComponentName thisWidget = new ComponentName(context, WidgetProvider.class);
int[] allWidgetIds = appWidgetManager.getAppWidgetIds(thisWidget);
for (int widgetId : allWidgetIds)
RemoteViews remoteViews = new RemoteViews(context.getPackageName(), R.layout.widget_layout);
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
// Set the text of the buttons
remoteViews.setTextViewText(R.id.widgetPreset1Button, prefs.getString("widget1", "Not set"));
remoteViews.setTextViewText(R.id.widgetPreset2Button, prefs.getString("widget2", "Not set"));
remoteViews.setTextViewText(R.id.widgetPreset3Button, prefs.getString("widget3", "Not set"));
remoteViews.setTextViewText(R.id.widgetPreset4Button, prefs.getString("widget4", "Not set"));
// Register the buttons with an OnClick event
Intent intent1 = new Intent("myapp.SendWidgetPreset");
intent1.putExtra("Widget", 1);
PendingIntent pendingIntent1 = PendingIntent.getBroadcast(context, 0, intent1, PendingIntent.FLAG_UPDATE_CURRENT);
remoteViews.setOnClickPendingIntent(R.id.widgetPreset1Button, pendingIntent1);
Intent intent2 = new Intent("myapp.SendWidgetPreset");
intent2.putExtra("Widget", 2);
PendingIntent pendingIntent2 = PendingIntent.getBroadcast(context, 0, intent2, PendingIntent.FLAG_UPDATE_CURRENT);
remoteViews.setOnClickPendingIntent(R.id.widgetPreset2Button, pendingIntent2);
Intent intent3 = new Intent("myapp.SendWidgetPreset");
intent3.putExtra("Widget", 3);
PendingIntent pendingIntent3 = PendingIntent.getBroadcast(context, 0, intent3, PendingIntent.FLAG_UPDATE_CURRENT);
remoteViews.setOnClickPendingIntent(R.id.widgetPreset3Button, pendingIntent3);
Intent intent4 = new Intent("myapp.SendWidgetPreset");
intent4.putExtra("Widget", 4);
PendingIntent pendingIntent4 = PendingIntent.getBroadcast(context, 0, intent4, PendingIntent.FLAG_UPDATE_CURRENT);
remoteViews.setOnClickPendingIntent(R.id.widgetPreset4Button, pendingIntent4);
new WidgetBroadcastReceiver();
appWidgetManager.updateAppWidget(widgetId, remoteViews);
和广播接收器:
public class WidgetBroadcastReceiver extends BroadcastReceiver
public WidgetBroadcastReceiver()
@Override
public void onReceive(Context context, Intent arg1)
int widget = arg1.getIntExtra("Widget", -1);
Toast.makeText(context, "Widget pressed: " + widget, Toast.LENGTH_SHORT).show();
我的问题是无论按下哪个按钮,它总是显示Widget pressed: 4
。如果我将intent4
、intent4.putExtra()
、pendingIntent4
和remoteViews.setOnClickPendingIntent()
这四行放在所有其他意图之上,那么它总是会说Widget pressed: 3
。换句话说,无论最后一个意图注册是什么,它都是在 Toast 消息中显示的小部件。
有人知道为什么这不能按我想要的方式工作吗?
【问题讨论】:
【参考方案1】:您需要为每个pendingintent ex 提供单独的请求代码:
PendingIntent pendingIntent1 = PendingIntent.getBroadcast(context, 0, intent1, PendingIntent.FLAG_UPDATE_CURRENT);
PendingIntent pendingIntent1 = PendingIntent.getBroadcast(context, 1/*request code*/, intent1, PendingIntent.FLAG_UPDATE_CURRENT);
【讨论】:
如果您在代码周围使用代码标签,它将使您的答案更具可读性:) 遇到了同样的问题...这对我来说确实有效:) 干杯【参考方案2】:您的 PendingIntent 正在被下一个覆盖。这是因为它们比较被封装的 Intent,并且在比较 Intent 时不考虑额外内容。为每个意图执行此操作:
Intent intent1 = new Intent("myapp.SendWidgetPreset");
intent1.putExtra("Widget", 1);
// This line makes your intents different
intent1.setData(Uri.parse(intent1.toUri(Intent.URI_INTENT_SCHEME)));
PendingIntent pendingIntent1 = PendingIntent.getBroadcast(context, 0, intent1, PendingIntent.FLAG_UPDATE_CURRENT);
remoteViews.setOnClickPendingIntent(R.id.widgetPreset1Button, pendingIntent1);
【讨论】:
有趣!我尝试为每个意图添加 .setData() 行,但现在根本不显示 Toast 消息。关于尝试什么的任何其他想法? 有人吗?我仍然无法弄清楚这一点。 @BarryBostwick 如果您使用 .setData(),则需要更新 androidManifest.xml 中的 Intent Filter 以匹配您放入 setData() 的任何内容。我会发布一个详细的答案。 @Karakuri re: Baker 的评论,鉴于上面推荐的“...setData()”代码行,您需要在 AndroidManifest 中添加什么 元素?【参考方案3】:似乎 PendingIntent.getBroadcast() 将忽略 requestCode(与 PendingIntent.getActivity 不同)。
因此,要制作独特的 PendingIntent,您可以为 Intent 提供数据。
例子:
public static Intent makeUniqueIntent(String action, int requestCode)
Intent intent = new Intent(action);
intent.setData(Uri.parse("http://"+ String.valueOf(requestCode)));
return intent;
然后像往常一样制作你的 Pending Intent,包括 requestCode。
PendingIntent.getBroadcast(ctx, request_code,
makeUniqueIntent(NotificationReceiver.INTENT, request_code),
PendingIntent.FLAG_CANCEL_CURRENT);
使用 Intent 中的 Data 元素,AndroidManifest.xml 中的匹配 Intent 过滤器也必须具有 Data 元素:
<receiver android:name=".service.NotificationReceiver">
<intent-filter>
<action android:name="my.package.my_action_string"/>
<data android:scheme="http"/>
</intent-filter>
</receiver>
上述意图过滤器仅识别出一个方案(即“http”)。因此,任何具有该方案的 Uri 都将匹配此过滤器的“数据”元素,并且将调用相应的 Receiver 类。
注意事项:
NotificationReceiver 是我的类,扩展 BroadcastReceiver NotificationReceiver.INTENT 是我在 NotificationReceiver 中声明的字符串常量。在此示例中,它将等于“my.package.my_action_string”; request_code 可以是任何东西。如果您想在将来引用相同的 Pending Intent(例如取消使用它的警报),请将其设为唯一并保存。有关使用 Intent 过滤器进行数据测试的更多信息:
http://developer.android.com/guide/components/intents-filters.html#DataTest
【讨论】:
intent-filter 的 元素中的方案使用“http”是否足够?还是应该使用您在 setData() 方法中显示的“http://”? 根据Android官方示例,不带斜线的“http”是正确的语法:developer.android.com/training/app-links/deep-linking以上是关于发送多种意图的小部件的主要内容,如果未能解决你的问题,请参考以下文章
无法从小部件发送待处理的意图,SendIntentException