Android 小部件,RemoteViews 上的 Intent 未在存在的数据中触发
Android Widget, Intent on RemoteViews not fired in data present
在我的 AppWidgetProvider class 中,我通过 RemoteViews 以编程方式将一些按钮添加到主布局:
static void updateAppWidget(......) {
..
RemoteViews views = new RemoteViews(context.getPackageName(), R.layout.main_widget);
for (int i=0; i<maxViews, 4); ++i) {
RemoteViews button = new RemoteViews(context.getPackageName(), R.layout.my_button);
String number = numbers.get(i).getCode();
// Test1
Intent actionIntent = new Intent("MyIntent");
PendingIntent pendingIntent = PendingIntent.getBroadcast(context, 0, actionIntent, 0);
button.setOnClickPendingIntent(R.id.image, pendingIntent);
// Test2
Intent actionIntent = new Intent("MyIntent");
actionIntent.setData(Uri.parse("tel:" + number));
PendingIntent pendingIntent = PendingIntent.getBroadcast(context, 0, actionIntent, 0);
button.setOnClickPendingIntent(R.id.image, pendingIntent);
// Test3
Intent actionIntent = new Intent("MyIntent");
actionIntent.putExtra("number", number);
PendingIntent pendingIntent = PendingIntent.getBroadcast(context, 0, actionIntent, 0);
button.setOnClickPendingIntent(R.id.image, pendingIntent);
views.addView(R.id.content_layout, button);
}
...
}
@Override
public void onReceive(Context context, Intent intent) {
System.out.println("Action: "+intent.getAction());
...
}
这里是清单:
<receiver android:name=".widget.EmergencyWidget" >
<intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
<action android:name="MyIntent" />
</intent-filter>
<meta-data
android:name="android.appwidget.provider"
android:resource="@xml/my_widget_info" />
</receiver>
使用 Test1 中的代码,单击按钮时,onReceive
方法被正确触发。
使用 Test2 中的代码,当点击按钮时,onReceive
方法没有触发。
使用 Test3 中的代码,当点击按钮时,onReceive
方法被触发但是 intent.hasExtra("number")
returns 错误。
我的代码有什么问题?
测试 1 有效,因为该操作与您的清单相匹配,正如您所期望的那样,并且正确处理了隐式意图。
根据 IntentFilter,如果您同时声明了操作和数据,则两者都需要匹配才能匹配意图 - 因为您没有在清单中声明 <data>
元素,它将永远不匹配。
您可以改用以下方法修复清单:
<receiver android:name=".widget.EmergencyWidget" >
<intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
<action android:name="MyIntent" />
</intent-filter>
<intent-filter>
<action android:name="MyIntent" />
<category android:name="android.intent.category.DEFAULT" />
<data android:scheme="tel" />
</intent-filter>
<meta-data
android:name="android.appwidget.provider"
android:resource="@xml/my_widget_info" />
</receiver>
或者通过将 setClassName(context, EmergencyWidget.class)
添加到您的 Intent
- 这将使它成为一个明确的 Intent
并且您不需要向清单添加任何内容(<intent-filter>
仅用于 Android 需要确定需要调用哪个组件的隐式 Intent。
您的 Test3 遇到了与 PendingIntent: if two PendingIntents match another by Intent.filterEquals 相关的 android 优化,然后它将重用现有的 PendingIntent
- extras 不考虑它们是否相等,因此系统可能有一个 PendingIntent 没有任何它正在重复使用的额外内容(它们只有在重新启动您的设备时才会被清除)。在这种情况下,您可以使用
PendingIntent pendingIntent = PendingIntent.getBroadcast(context, 0, actionIntent,
PendingIntent.FLAG_UPDATE_CURRENT);
FLAG_UPDATE_CURRENT 告诉 Android 在构建 PendingIntent
时替换额外的部分。
在我的 AppWidgetProvider class 中,我通过 RemoteViews 以编程方式将一些按钮添加到主布局:
static void updateAppWidget(......) {
..
RemoteViews views = new RemoteViews(context.getPackageName(), R.layout.main_widget);
for (int i=0; i<maxViews, 4); ++i) {
RemoteViews button = new RemoteViews(context.getPackageName(), R.layout.my_button);
String number = numbers.get(i).getCode();
// Test1
Intent actionIntent = new Intent("MyIntent");
PendingIntent pendingIntent = PendingIntent.getBroadcast(context, 0, actionIntent, 0);
button.setOnClickPendingIntent(R.id.image, pendingIntent);
// Test2
Intent actionIntent = new Intent("MyIntent");
actionIntent.setData(Uri.parse("tel:" + number));
PendingIntent pendingIntent = PendingIntent.getBroadcast(context, 0, actionIntent, 0);
button.setOnClickPendingIntent(R.id.image, pendingIntent);
// Test3
Intent actionIntent = new Intent("MyIntent");
actionIntent.putExtra("number", number);
PendingIntent pendingIntent = PendingIntent.getBroadcast(context, 0, actionIntent, 0);
button.setOnClickPendingIntent(R.id.image, pendingIntent);
views.addView(R.id.content_layout, button);
}
...
}
@Override
public void onReceive(Context context, Intent intent) {
System.out.println("Action: "+intent.getAction());
...
}
这里是清单:
<receiver android:name=".widget.EmergencyWidget" >
<intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
<action android:name="MyIntent" />
</intent-filter>
<meta-data
android:name="android.appwidget.provider"
android:resource="@xml/my_widget_info" />
</receiver>
使用 Test1 中的代码,单击按钮时,onReceive
方法被正确触发。
使用 Test2 中的代码,当点击按钮时,onReceive
方法没有触发。
使用 Test3 中的代码,当点击按钮时,onReceive
方法被触发但是 intent.hasExtra("number")
returns 错误。
我的代码有什么问题?
测试 1 有效,因为该操作与您的清单相匹配,正如您所期望的那样,并且正确处理了隐式意图。
根据 IntentFilter,如果您同时声明了操作和数据,则两者都需要匹配才能匹配意图 - 因为您没有在清单中声明 <data>
元素,它将永远不匹配。
您可以改用以下方法修复清单:
<receiver android:name=".widget.EmergencyWidget" >
<intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
<action android:name="MyIntent" />
</intent-filter>
<intent-filter>
<action android:name="MyIntent" />
<category android:name="android.intent.category.DEFAULT" />
<data android:scheme="tel" />
</intent-filter>
<meta-data
android:name="android.appwidget.provider"
android:resource="@xml/my_widget_info" />
</receiver>
或者通过将 setClassName(context, EmergencyWidget.class)
添加到您的 Intent
- 这将使它成为一个明确的 Intent
并且您不需要向清单添加任何内容(<intent-filter>
仅用于 Android 需要确定需要调用哪个组件的隐式 Intent。
您的 Test3 遇到了与 PendingIntent: if two PendingIntents match another by Intent.filterEquals 相关的 android 优化,然后它将重用现有的 PendingIntent
- extras 不考虑它们是否相等,因此系统可能有一个 PendingIntent 没有任何它正在重复使用的额外内容(它们只有在重新启动您的设备时才会被清除)。在这种情况下,您可以使用
PendingIntent pendingIntent = PendingIntent.getBroadcast(context, 0, actionIntent,
PendingIntent.FLAG_UPDATE_CURRENT);
FLAG_UPDATE_CURRENT 告诉 Android 在构建 PendingIntent
时替换额外的部分。