是否可以使用相同的 requestCode 和不同的 extra 创建多个 PendingIntent?

Posted

技术标签:

【中文标题】是否可以使用相同的 requestCode 和不同的 extra 创建多个 PendingIntent?【英文标题】:Is it possible to create multiple PendingIntents with the same requestCode and different extras? 【发布时间】:2013-12-10 20:10:56 【问题描述】:

我正在使用 AlarmManager 来安排 1 到 35 个警报之间的任意位置(取决于用户输入)。当用户请求安排新警报时,我需要取消当前警报,因此我使用相同的 requestCode 创建所有警报,在 final 变量中定义。

// clear remaining alarms
Intent intentstop = new Intent(this, NDService.class);
PendingIntent senderstop = PendingIntent.getService(this,
            NODIR_REQUESTCODE, intentstop, 0);
am.cancel(senderstop);

// loop through days
if (sched_slider.getBooleanValue())
for (int day = 1; day < 8; day++) 

    if (day == 1 && sun.isChecked())
                scheduleDay(day);
    if (day == 2 && mon.isChecked())
                scheduleDay(day);
    if (day == 3 && tue.isChecked())
                scheduleDay(day);
    if (day == 4 && wed.isChecked())
                scheduleDay(day);
    if (day == 5 && thu.isChecked())
                scheduleDay(day);
    if (day == 6 && fri.isChecked())
                scheduleDay(day);
    if (day == 7 && sat.isChecked())
                scheduleDay(day);


...

public void scheduleDay(int dayofweek) 
    Intent toolintent = new Intent(this, NDService.class);
    toolintent.putExtra("TOOL", "this value changes occasionally");
    PendingIntent pi = PendingIntent.getService(this,
                NODIR_REQUESTCODE, toolintent, 0);
    calendar.set(Calendar.DAY_OF_WEEK, dayofweek);
    calendar.set(Calendar.HOUR_OF_DAY, hour);
    calendar.set(Calendar.MINUTE, minute);
    calendar.set(Calendar.SECOND, 0);
    am.setRepeating(AlarmManager.RTC, calendar.getTimeInMillis(),
                AlarmManager.INTERVAL_DAY * 7, pi);

在这里,如果用户选中了sun(这是一个复选框),它将安排在每个星期日在hourminute 运行警报。您可以看到以这种方式创建的每个警报都有相同的 requestCode,但 TOOL 的额外更改有时会针对每个警报。

但是,在我的测试中,当警报响起并且我的服务运行时,Intent 中的额外内容现在是 null。 This question 建议使用 PendingIntent.FLAG_CANCEL_CURRENT 可以解决这个问题,但那不会取消其他 PendingIntents 吗?

简而言之:

有人能解释一下 PendingIntents 是如何工作的吗?关于创建多个具有相同 requestCode 和不同附加项的内容?我应该使用哪些标志(如果有)?

【问题讨论】:

【参考方案1】:

实际上,您并没有“创建”PendingIntents。您从 android 框架中请求它们。当您从 Android 框架请求 PendingIntent 时,它会检查是否已经存在与您作为参数传递的条件匹配的 PendingIntent。如果是这样,它不会创建一个新的PendingIntent,它只是给你一个指向现有PendingIntent 的“令牌”。如果它没有找到匹配的PendingIntent,它将创建一个,然后返回一个指向它刚刚创建的那个的“令牌”。您可以设置一些标志来修改此行为,但不是那么多。这里最重要的是要了解 Android 框架进行匹配的方式。

为此,它会检查以下参数是否匹配(将现有的PendingIntent 与您传递的参数进行比较):

请求代码必须相同。否则它们不匹配。 Intent 中的“动作”必须相同(或均为空)。否则它们不匹配。 Intent 中的“数据”必须相同(或均为空)。否则它们不匹配。 Intent 中的(数据的)“类型”必须相同(或两者均为空)。否则它们不匹配。 Intent 中的“包”和/或“组件”必须相同(或均为空)。否则它们不匹配。 “包”和“组件”字段设置为“显式”Intents。 Intent 中的“类别”列表必须相同。否则它们不匹配。

您应该注意到“附加”不在上面的列表中。这意味着,如果您请求 PendingIntent,则当 Android 框架尝试查找匹配的 PendingIntent 时,不会考虑“附加”。这是开发人员常犯的错误。

我们现在可以解决您可以添加以修改 PendingIntent 请求的行为的其他标志:

FLAG_CANCEL_CURRENT - 指定此标志时,如果找到匹配的PendingIntent,则取消(删除、删除、无效)PendingIntent 并创建一个新标志。这意味着任何持有指向旧 PendingIntent 的“令牌”的应用程序都将无法使用它,因为它不再有效。

FLAG_NO_CREATE - 指定此标志时,如果找到匹配的PendingIntent,则返回指向现有PendingIntent 的“令牌”(这是通常的行为)。但是,如果没有找到匹配的PendingIntent,则不会创建一个新的,并且调用只会返回null。这可用于确定是否有针对特定参数集的活动PendingIntent

FLAG_ONE_SHOT - 当您指定此标志时,创建的PendingIntent 只能使用一次。这意味着,如果您将此 PendingIntent 的“令牌”提供给多个应用程序,则在首次使用 PendingIntent 后,它将被取消(删除、删除、无效),因此以后任何尝试使用它都会失败。

FLAG_UPDATE_CURRENT - 指定此标志时,如果找到匹配的 PendingIntent,则 PendingIntent 中的“附加”将替换为您作为参数传递的 Intent 中的“附加”到getxxx() 方法。如果找不到匹配的PendingIntent,则会创建一个新的(这是正常行为)。这可用于更改现有PendingIntent 上的“额外”,您已经将“令牌”提供给其他应用程序并且不想使现有PendingIntent 无效。

让我尝试解决您的具体问题:

如果请求代码、操作、数据、类型和包/组件参数相同,则系统中不能有多个活动PendingIntent。因此,您无法要求能够拥有多达 35 个活动的PendingIntents,它们都具有相同的请求代码、操作、数据、类型和包/组件参数,但具有不同的“附加”。

我建议您使用 35 个不同的请求代码,或者为您的 Intent 创建 35 个不同的唯一“操作”参数。

【讨论】:

感谢您的帮助!我的意图没有数据或操作,所以你是说我可能会随机化其中一个字段?如果我这样做,我真的不需要担心标志吗? 哦,我刚刚也想到了一些东西。如果我随机化,比如说,Action,那么我的代码的“清除警报”部分将不起作用。我必须记录随机操作并将 Intents 操作设置为循环以清除所有警报,对吗? 是的,你会的。这正是您需要做的。 谢谢。 Android 文档在这方面不是很好……这是唯一对我有意义的解释。 非常感谢您提供如此详细的回答【参考方案2】:

是的,可以为每个警报设置独特的意图操作

intent.setAction("uniqueCode");

Intent intent = new Intent(context, MyAlarmReciver.class);
intent.setAction("uniqueCode");
PendingIntent pendingIntent = PendingIntent.getBroadcast(activity, 0,   intent, 0);
AlarmManager alarmManager = (AlarmManager)       context.getSystemService(activity.ALARM_SERVICE);
Calendar c = Calendar.getInstance();
c.add(Calendar.MINUTE, 1);
alarmManager.set(AlarmManager.RTC_WAKEUP, c.getTimeInMillis(),   pendingIntent);

【讨论】:

以上是关于是否可以使用相同的 requestCode 和不同的 extra 创建多个 PendingIntent?的主要内容,如果未能解决你的问题,请参考以下文章

java 获取全局唯一的整形常量,可以用于requestCode的定义,防止其在不同文件中定义时值的碰撞。

Android:requestCode 和 resultCode

requestCode 代表啥?

如何在android报警时从待处理的意图中获取requestCode

使用registerForActivityResult替代onActivityResult

android,,onActivityResult的作用是啥啊,requestCode, resultCode是啥意思啊?