PendingIntent 上使用的“requestCode”是啥?

Posted

技术标签:

【中文标题】PendingIntent 上使用的“requestCode”是啥?【英文标题】:What's "requestCode" used for on PendingIntent?PendingIntent 上使用的“requestCode”是什么? 【发布时间】:2014-02-26 21:03:55 【问题描述】:

背景:

我正在通过 AlarmManager 使用 PendingIntent 进行警报。

问题:

一开始我以为要取消之前的,我必须提供我之前用来启动警报的确切 requestCode。

但后来我发现我错了,正如cancellation API 所说:

删除任何具有匹配 Intent 的警报。任何警报,任何类型, 其 Intent 与此匹配(由 filterEquals(Intent) 定义), 将被取消。

看着“filterEquals”,文档说:

根据意图的目的确定两个意图是否相同 分辨率(过滤)。也就是说,如果他们的动作、数据、类型、类、 和类别是一样的。这不会比较任何额外的数据 包含在意图中。

所以我不明白“requestCode”的用途......

问题:

“requestCode”是做什么用的?

如果我使用相同的“requestCode”创建多个警报怎么办?它们会相互覆盖吗?

【问题讨论】:

如果你使用相同的 requestCode 你会得到相同的 PendingIntent 对于 PendingIntent.getBroadcast(),android 显然忽略了 requestCode。从 API 22 开始,它不会使您的 Pending Intent 独一无二。用于 getActivity() (可能还有 getService() 但我没有测试过)。 ***.com/a/33203752/2301224 @Baker 这不被认为是一个错误吗?如果这是一个错误,你应该在这里写下它:code.google.com/p/android/issues/list 嗯,实际上,文档确实指定了 requestiCode 的用法:If you truly need multiple distinct PendingIntent objects active at the same time (such as to use as two notifications that are both shown at the same time), then you will need to ensure there is something that is different about them to associate them with different PendingIntents. This may be any of the Intent attributes considered by Intent#filterEquals(Intent), or different request code integers supplied. @Eir 对,那么使用 requestCode 有什么意义呢?可以在哪里使用? 【参考方案1】:
    requestCode 用于稍后检索相同的待处理意图实例(用于取消等)。 是的,我猜警报会相互覆盖。我会保持请求代码的唯一性。

【讨论】:

是否将 requestCode 设置为唯一需要的,即使警报的意图非常不同(例如,一个用于服务 A,一个用于服务 B)?另外,为什么文档没有说明呢?无论requestCode是什么,是否可以删除某种类型的所有警报? 不,不同的意图没有必要。而且我不知道为什么文档没有说明任何内容,但我在设置重复警报以及使用相同意图时了解到这一点。 我说的是 PendingIntent 。 startActivityForResult 使用正常的意图。 “startActivityForResult with PendingIntent 使用代理活动”的目的是什么?可以举个例子吗? 我同意; PendingIntent 和 AlarmManager 的文档完全是 sh!t - 由于无法以编程方式列出警报,因此变得更糟。【参考方案2】:

我只想添加到@Minhaj Arfin 的答案

1- requestCode 用于稍后获取相同的待处理意图(用于取消等)

2- 是的,只要您为您在 PendingIntent 上指定的 Intent 指定相同的接收方,它们就会被覆盖

示例:

Intent startIntent1 = new Intent(context, AlarmReceiverFirst.class);
PendingIntent pendingIntent1 = PendingIntent.getBroadcast(context, 0, startIntent1, 0);

Intent startIntent2 = new Intent(context, AlarmReceiverSecond.class);
PendingIntent pendingIntent2 = PendingIntent.getBroadcast(context, 0, startIntent2, 0);

从上面的例子中,他们不会互相覆盖因为接收者不同(AlarmReceiverFirst和AlarmReceiverSecond)

Intent startIntent2 = new Intent(context, AlarmReceiverSecond.class);
PendingIntent pendingIntent2 = PendingIntent.getBroadcast(context, 0, startIntent2, 0);

Intent startIntent3 = new Intent(context, AlarmReceiverSecond.class);
PendingIntent pendingIntent3 = PendingIntent.getBroadcast(context, 0, startIntent3, 0);

从上面的例子中,他们相互覆盖,因为接收者是相同的(AlarmReceiverSecond)

【讨论】:

Intent startIntent4 = new Intent(context, AlarmReceiverSecond.class); PendingIntent pendingIntent4 = PendingIntent.getService(context, 0, startIntent4, 0);那会好吗?我的意思是,这不会因为它调用 getService() 而不是 getBroadcast() 而被覆盖吗? 抱歉再问一个问题,但是因为***不允许我写一个没有单个代码行的问题.. PendingIntent方法的最后一个参数像getBroadcast()有什么关系压倒一切?我曾经把 0 放在那里,就像你上面的示例代码一样,但我也看到很多人都放了一些特定的选项值而不是 0。 @Jenix 你在意图上使用AlarmReceiverSecond.class,然后使用PendingIntent.getService()。它不起作用,因为AlarmReceiverSecond.classBroadcastReceiver,而不是Service 关于标志,它是您可以设置的属性,这将使您的 PendingIntent 的行为根据您提供的标志。 0 表示所有标志关闭 啊我太傻了哈哈我到底在想什么..我对 PendingIntent 有点困惑,你的回答真的很有帮助。我只是想让它更清楚,但现在意识到我的问题一开始没有任何意义。谢谢!【参考方案3】:

其实documentation明确说明了请求码的用途:

如果您确实需要多个不同的 PendingIntent 对象在 同时(例如用作两个都显示的通知 同时),那么你需要确保有一些东西 他们的不同之处在于将它们与不同的 待定意图。这可能是考虑的任何 Intent 属性 Intent#filterEquals(Intent),或不同的请求代码整数 提供给 getActivity(Context, int, Intent, int), getActivities(上下文,int,Intent[],int),getBroadcast(上下文,int, Intent, int) 或 getService(Context, int, Intent, int)。

既然好像还不是很清楚,我来解释一下:

当您想使用PendingIntent 对象时,您不只是实例化一个。相反,您可以使用PendingIntent 静态方法(getActivitygetBroadcastgetService 等)从系统中获取一个。系统保留一堆 PendingIntent 实例并给你一个。它给了你哪一个,这取决于你传递给这些 getter 方法的输入参数。这些输入参数是:Context,即意图的目标接收者、要使用的IntentrequestCodeflags。当您传递相同的Context、相同的requestCode 和相同的Intent(意味着filterEquals 与另一个意图的意图)时,您将获得相同的PendingIntent 对象。关键是系统希望拥有尽可能少的PendingIntent 对象,因此它倾向于尽可能重用现有的对象。

例如,您有两个日历通知,针对两个不同的日期。当您单击其中一个时,您希望您的应用程序打开到该通知的相应日期。在这种情况下,您具有相同的Context 目标,而您传递的Intent 对象仅在EXTRA_DATA(指定应该打开的日期)中有所不同。如果您在获取PendingIntent 对象时提供相同的requestCode,那么您最终将得到相同的PendingIntent 对象。因此,在创建第二个通知时,您将用新的 EXTRA_DATA 替换旧的 Intent 对象,并最终得到两个指向同一日期的通知。

如果您想拥有两个不同的PendingIntent 对象,就像在这种情况下应该做的那样,您应该在获取PendingIntent 对象时指定不同的requestCode

【讨论】:

但正如我所提到的,要取消警报,您不能只使用 requestCode。这对它没有任何意义。您将不得不添加额外的数据来区分它们。我不记得了,但我认为您甚至可以将相同的 requestCode 用于多个警报。 @androiddeveloper 你刚才说的不正确。试试看。【参考方案4】:

在我的情况下,我想用两个不同的意图打开同一个活动,所以如果托盘中有两个或多个 FCMS,它们中的任何一个都只会打开另一个不会,所以我更改了待处理意图的请求代码成功了。

 PendingIntent pendingIntent =
                            PendingIntent.getActivity(this, **Some unique id for all GCMS** /* Request code */, intent,
                                    PendingIntent.FLAG_ONE_SHOT);

【讨论】:

我的情况不需要进一步检查代码,你能告诉我在哪种情况下需要挂起的意图实例。关于问题更改请求代码帮助我转到正确的屏幕,我不知道这是否是正确的方法,对我来说,只有当托盘中有多个 FCM 时才会发生错误 那么,如果您不需要它,为什么要设置不同的请求代码? 好的,我将详细解释,我有一些活动 A,它旨在显示问题,我将通过意图从通知中传递 id,然后对该 id 进行网络请求并获取特定问题,那么当通知托盘中有多个通知然后我单击其中任何一个时,会发生什么情况有效。我希望我现在说清楚了,如果需要更多讨论,我也在那里,我也想了解更多,谢谢 哦,您的意思是,否则它根本不会起作用,对吧?很抱歉造成混乱。这个问题很久以前就问过了,完全不记得了……【参考方案5】:

requestCode 的一件重要的事情会严重困扰您的应用程序,那就是使用小部件时。 如果它们的requestCode 相同,则手机重启后小部件将无法工作。 这意味着您在小部件的remoteViews 上设置的pendingIndent 必须设置唯一的requestCode,通常是带有数字的widgetId。

【讨论】:

【参考方案6】:

在构建 PendingIntent 时,您需要提供一个名为 requestCode 的整数。官方文档指出这是“发件人的私人请求代码”。但是,请求代码也是区分 PendingIntent 实例的基本方法。你看,getBroadcast() 方法不仅仅是一个用于创建 PendingIntent 实例的静态工厂

【讨论】:

以上是关于PendingIntent 上使用的“requestCode”是啥?的主要内容,如果未能解决你的问题,请参考以下文章

广播接收器未接收到意图 (RemoteViews / PendingIntent)

面试官:说一下 PendingIntent 和 Intent 的区别

PendingInent 创建的 Android 任务无法再次使用 pendingIntent 启动另一个活动

解决PendingIntent传递参数为空的问题

PendingIntent劫持导致app任意文件读写漏洞

PendingIntent劫持导致app任意文件读写漏洞