PendingIntent

在Android中,我们常常使用PendingIntent来表达一种“留待日后处理”的意思。从这个角度来说,PendingIntent可以被理解为一种特殊的异步处理机制。不过,单就命名而言,PendingIntent其实具有一定误导性,因为它既不继承于Intent,也不包含Intent,它的核心可以粗略地汇总成四个字——“异步激发”。
很明显,这种异步激发常常是要跨进程执行的。比如说A进程作为发起端,它可以从系统“获取”一个PendingIntent,然后A进程可以将PendingIntent对象通过binder机制“传递”给B进程,再由B进程在未来某个合适时机,“回调”PendingIntent对象的send()动作,完成激发。

PendingIntent 是 Android 提供的一种用于外部程序调起自身程序的能力,生命周期不与主程序相关。外部程序通过 PendingIntent 只能调用起三种组件:

  • Activity
  • Service
  • Broadcast

PendingIntent 的使用场景有三个:

  • 使用 AlarmManager 设定闹钟
  • 在系统状态栏显示 Notification
  • 在桌面显示 Widget

PendingIntent 也只能通过下列的静态方法获取:

1
2
3
4
5
6
7
8
9
// 获取 Broadcast 关联的 PendingIntent
PendingIntent.getBroadcast(Context context, int requestCode, Intent intent, int flags)

// 获取 Activity 关联的 PendingIntent
PendingIntent.getActivity(Context context, int requestCode, Intent intent, int flags)
PendingIntent.getActivity(Context context, int requestCode, Intent intent, int flags, Bundle options)

// 获取 Service 关联的 PendingIntent
PendingIntent.getService(Context context, int requestCode, Intent intent, int flags)

坦白说,这几个函数的命名可真不怎么样,所以我们简单解释一下。上面的getActivity()的意思其实是,获取一个PendingIntent对象,而且该对象日后激发时所做的事情是启动一个新activity。也就是说,当它异步激发时,会执行类似Context.startActivity()那样的动作。相应地,getBroadcast()getService()所获取的PendingIntent对象在激发时,会分别执行类似Context.sendBroadcast()Context.startService()这样的动作。

参数flags在文档中是这样解析的:

**flags:**目前为止只提供FLAG_ONE_SHOT, FLAG_NO_CREATE, FLAG_CANCEL_CURRENT, FLAG_UPDATE_CURRENT这四个flag

**FLAG_ONE_SHOT:**利用 FLAG_ONE_SHOT获取的PendingIntent只能使用一次,即使再次利用上面三个方法重新获取,再使用PendingIntent也将失败。

**FLAG_NO_CREATE:**利用FLAG_NO_CREAT获取的PendingIntent,若描述的Intent不存在则返回NULL值.

**FLAG_CANCEL_CURRENT:**如果描述的PendingIntent已经存在,则在产生新的Intent之前会先取消掉当前的。你可用使用它去检索新的Intent,如果你只是想改变Intent中的额外数据的话。通过取消先前的Intent,可用确保只有最新的实体可用启动它。如果这一保证不是问题,考虑flag_update_current。

**FLAG_UPDATE_CURRENT:**最经常使用的是FLAG_UPDATE_CURRENT,因为描述的Intent有 更新的时候需要用到这个flag去更新你的描述,否则组件在下次事件发生或时间到达的时候extras永远是第一次Intent的extras。

上面4个flag中最经常使用的是FLAG_UPDATE_CURRENT,因为描述的Intent有 更新的时候需要用到这个flag去更新你的描述,否则组件在下次事件发生或时间到达的时候extras永远是第一次Intent的extras。
使用 FLAG_CANCEL_CURRENT也能做到更新extras,只不过是先把前面的extras清除,另外FLAG_CANCEL_CURRENT和 FLAG_UPDATE_CURRENT的区别在于能否新new一个Intent,FLAG_UPDATE_CURRENT能够新new一个 Intent,而FLAG_CANCEL_CURRENT则不能,只能使用第一次的Intent。

此外还需要注意参数:
int requestCode: Private request code for the sender (currently not used).

PendingIntent contentIntent = PendingIntent.getActivity(context, num, intent, PendingIntent.FLAG_UPDATE_CURRENT);

对于FLAG_UPDATE_CURRENT,如果上面的requestCode 为常量,则对于先后出现的若干Notification,则所有对应的Intent里面的extra被更新为最新的,就是全部同一为最后一次的。
相反,如果num每次不一样,则里面的Inent的数据没被更新。
对于FLAG_CANCEL_CURRENT,则只响应最前面的第一条Notifiacation,后面所有的不响应….

使用请参考:Android中的PendingIntent传送widgetID总是最后一个


flags:

(1) android.app.PendingIntent.FLAG_UPDATE_CURRENT
如果PendingIntent已经存在,保留它并且只替换它的extra数据。

(2) android.app.PendingIntent.FLAG_CANCEL_CURRENT
如果PendingIntent已经存在,那么当前的PendingIntent会取消掉,然后产生一个新的PendingIntent。

(3) android.app.PendingIntent.FLAG_ONE_SHOT
PendingIntent只能使用一次。调用了实例方法send()之后,它会被自动cancel掉,再次调用send()方法将失败。

(4) android.app.PendingIntent.FLAG_NO_CREATE
如果PendingIntent不存在,简单了当返回null。

requestCode:

如果一次推送几个通知到通知栏,且requestCode一致的话,PendingIntent里里边的数据会被最后一个推送过来的替换掉,即:第一个推送的数据会跟第二个一样。这点一定要注意。