博客原文: [11月的好奇心] PendingIntent 是啥?为何不少场景不能直接用 Intent 非要用 PendingIntent?bash
出于对 PendingIntent 的好奇心,翻阅了不少资料。最后发现仍是官方文档描述地到位。前三段话读下去已经解决了个人大部分疑惑。整篇读完有种豁然开朗的快感。 等翻译完,开始有点不解本身最初居然会有为何不直接使用 Intent 代替 PendingIntent? 这样的问题。网络
总之,对于对 PendingIntent 尚有疑问的同窗来讲,这文档是真不错。app
/**
* A description of an Intent and target action to perform with it. Instances
* of this class are created with {@link #getActivity}, {@link #getActivities},
* {@link #getBroadcast}, and {@link #getService}; the returned object can be
* handed to other applications so that they can perform the action you
* described on your behalf at a later time.
复制代码
这里说PendingIntent
是Intent
行为的描述类。相似于咱们用一个文件句柄,来讲明它所对应的文件。 它由这四个方法建立:getActivity
getActivities
getBroadcast
getService
。 它能够被其它应用调用以执行你预先声明的行为。less
这里能够这么对比理解: FileDescriptor 用来描述文件 Socket 用来描述网络 PendingIntent 用来描述行为ide
若是把类名改成
IntentDescriptor
或许会更好理解。ui
*
* <p>By giving a PendingIntent to another application,
* you are granting it the right to perform the operation you have specified
* as if the other application was yourself (with the same permissions and
* identity). As such, you should be careful about how you build the PendingIntent:
* almost always, for example, the base Intent you supply should have the component
* name explicitly set to one of your own components, to ensure it is ultimately
* sent there and nowhere else.
*
复制代码
把 PendingIntent
交给其它应用,你就授予了它们进行其所定义的行为的权利。 因此你建立 PendingIntent
必定要格外当心:记住在你定义的 Intent
中加上限制用的包名、类名,以确保它只被你但愿的对象使用。this
这段是在说,我不只告诉你你该作啥,连权限也给你了。spa
这搁在军营中,就是一道虎符啊。因此必定要声明好把虎符具体交到谁的手中,否则会很危险。翻译
* <p>A PendingIntent itself is simply a reference to a token maintained by
* the system describing the original data used to retrieve it. This means
* that, even if its owning application's process is killed, the * PendingIntent itself will remain usable from other processes that * have been given it. If the creating application later re-retrieves the * same kind of PendingIntent (same operation, same Intent action, data, * categories, and components, and same flags), it will receive a PendingIntent * representing the same token if that is still valid, and can thus call * {@link #cancel} to remove it. * 复制代码
咱们如今知道 PendingIntent
其实就是个 IntentDescriptor
行为描述符,可是它存到哪里了呢? maintained by the system,和文件同样,被系统维护。因此不管建立它的进程是否存在,它都和文件同样,被系统保存在了某个地方。只要你拥有“读取权限”,就能随时获取它。 若是建立 PendingIntent
的程序后来又要获取相同类型的 PendingIntent
(相同的操做、相同的 Intent
action、data、categories、component、flags),那么它会获取到和以前相同的 token, 前提是它仍然有效。此时你能够取消它,若是你但愿的话。code
* <p>Because of this behavior, it is important to know when two Intents
* are considered to be the same for purposes of retrieving a PendingIntent.
* A common mistake people make is to create multiple PendingIntent objects
* with Intents that only vary in their "extra" contents, expecting to get
* a different PendingIntent each time. This does <em>not</em> happen. The
* parts of the Intent that are used for matching are the same ones defined
* by {@link Intent#filterEquals(Intent) Intent.filterEquals}. If you use two
* Intent objects that are equivalent as per
* {@link Intent#filterEquals(Intent) Intent.filterEquals}, then you will get
* the same PendingIntent for both of them.
*
复制代码
这段说,上面说过使用两个相同的 Intent
会获取到同一个 PendingIntent
,那么什么样的 Intent
被认为是相同的呢? 不少人常犯的错误是,认为只改变 Intent#extra
内容就能够获取到不一样的 PendingIntent
。 而事实并不是如此。 Intent
是否相同经过 Intent.filterEquals
判断。见下图。只有这个方法返回 false
, 才能获得不一样的 PendingIntent
。
* <p>There are two typical ways to deal with this.
*
* <p>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
* {@link Intent#filterEquals(Intent) Intent.filterEquals}, or different
* request code integers supplied to {@link #getActivity}, {@link #getActivities},
* {@link #getBroadcast}, or {@link #getService}.
*
* <p>If you only need one PendingIntent active at a time for any of the
* Intents you will use, then you can alternatively use the flags
* {@link #FLAG_CANCEL_CURRENT} or {@link #FLAG_UPDATE_CURRENT} to either
* cancel or modify whatever current PendingIntent is associated with the
* Intent you are supplying.
*/
复制代码
这段就比较啰嗦了,简单两句话说明
在某些场景有两种方法来避免获取到相同 PendingIntent
:
Intent#filterEquals
中做为判断一句的某个字段PendingIntent
时使用不一样的 requestCode
若是你有多个不一样的 Intent
,但你只须要一个活动的 PendingIntent
。那么你须要经过和它绑定的 Intent
来更新或移除它。