昨天帮朋友使用Android开发定时提醒功能模块,咋看这个功能挺简单的,但是其中涉及到的东西还挺多,这里我主要挑了PendingIntent来做介绍。
什么是PendingIntent?
简单来说,PendingIntent其实就是用来指定在某个操作之后,下一步做什么。打个比方:老大说我们在项目完成之后就要发奖金,发奖金这件事情在项目完成之后将触发的操作,就相于PendingIntent。
什么时候会用PendingIntent?
PendingIntent通常会用在定时提醒及发送Notification消息时,用来指定到达指定时间及点击Notification消息之后的操作。例如以下代码:
AlarmManager alarmManager = (AlarmManager)getSystemService(ALARM_SERVICE); alarmManager.setRepeating(AlarmManager.RTC_WAKEUP,task.getDateTime().getMillis(), 30*1000, pendingIntent);
上述代码是一个定时提醒的功能,pendingIntent参数用于指定到达指定时间是该做何种操作。
PendingIntent提供的操作?
目前PendingIntent提供了三项操作:启动Activity、启动Service以及发送广播,它的实例化是通过
PendingIntent的三个静态方法来完成, getActivity(Context, int, Intent, int)
, getBroadcast(Context, int, Intent, int)
, getService(Context, int, Intent, int),
这三个方法与前面三项操作是一一对应的。
PendingIntent参数解释
以 getActivity
为例我们来介绍PendingIntent参数。SDK的API中对 getActivity
是这样解释的:
这里我们主要介绍flags参数,这个参数比较重要,也较难理解。继续阅读API文档,文档告诉我们flags可能的值有如下几个:FLAG_ONE_SHOT
, FLAG_NO_CREATE
, FLAG_CANCEL_CURRENT
, FLAG_UPDATE_CURRENT
。
现在我们分别来看看这几个值是什么意思:
这个参数的含义是:当做了启动Activity这件事情之后,后面再去做启动Activity这件事,都是无效的。
这个参数的含义是:如果PendingIntent不存在,那么直接返回null而不创建。一般来说这个用的比较少。
这个参数的含义是:如果PendingIntent如果存在的话,那么首先取消它,然后再创建。
这个参数的含义是:PendingIntent如果存在,那么继续保持它,并用新的Intent里面的Extras数据替换这个PendingIntent里面Intent的Extras数据。
PendingIntent存在性判定
看到上面PendingIntent参数的解释,我们发现这几个参数大多与PendingIntent的存在性有关。那么通过getActivity这个方法拿到的PendingIntent是已经存在的还是新创建的?这里我们通过阅读源码来找到问题的答案。首先找到PendingIntent.getActivity方法。
public static PendingIntent getActivity(Context context, int requestCode, Intent intent, int flags, Bundle options) { String packageName = context.getPackageName(); String resolvedType = intent != null ? intent.resolveTypeIfNeeded( context.getContentResolver()) : null; try { intent.setAllowFds(false); IIntentSender target = ActivityManagerNative.getDefault().getIntentSender( ActivityManager.INTENT_SENDER_ACTIVITY, packageName, null, null, requestCode, new Intent[] { intent }, resolvedType != null ? new String[] { resolvedType } : null, flags, options, UserHandle.myUserId()); return target != null ? new PendingIntent(target) : null; } catch (RemoteException e) { } return null; }
从这个方法里面,我们发现,PendingIntent是跟Target有关,并且每次拿到的PendingIntent的内存地址都不是同一个,所以PendingIntent不是通过"=="运算来比较存在性的,我们找到PendingIntent的equals方法。
@Override public boolean equals(Object otherObj) { if (otherObj instanceof PendingIntent) { return mTarget.asBinder().equals(((PendingIntent)otherObj) .mTarget.asBinder()); } return false; }
我们发现是比较mTarget的Binder,那mTarget是什么?mTarget就是我们getActivity方法里面见到的target,所以这里我们可以说:PendingIntent存在性是与mTarget有关,而与PendingIntent本身无关。
通过target的获取方式,我们不难猜测一下target存在性是与request,intent,context有关。我们再结合API文档来看一下:
这里描述的是与operation、intent的action、data、categories等等有关。所以如果要让两个PendingIntent不同,可以通过设置intent的data参数:例如:intent2.setData(Uri.parse("task://12");同样你也可以改变其他值来让PendingIntent不同。
再结合上面 FLAG_ONE_SHOT
, FLAG_NO_CREATE
, FLAG_CANCEL_CURRENT
, FLAG_UPDATE_CURRENT
来理解一下。
FLAG_ONE_SHOT->target是否相同->如果相同则看send()方法是否调用->如果已经调用了,则不做任何操作。
FLAG_NO_CREATE
->target是否存在->如果不存在返回nullFLAG_CANCEL_CURRENT
->target是否存在->如果存在则取消操作,重新生成一个targetFLAG_UPDATE_CURRENT->target是否存在->保持target,将intent的extras值更新
好了,以上是本人的一些浅见,希望对你有所帮助!