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 时替换额外的部分。