昨天帮朋友使用Android开发定时提醒功能模块,咋看这个功能挺简单的,但是其中涉及到的东西还挺多,这里我主要挑了PendingIntent来做介绍。

什么是PendingIntent?

简单来说,PendingIntent其实就是用来指定在某个操作之后,下一步做什么。打个比方:老大说我们在项目完成之后就要发奖金,发奖金这件事情在项目完成之后将触发的操作,就相于PendingIntent。

什么时候会用PendingIntent?

PendingIntent通常会用在定时提醒及发送Notification消息时,用来指定到达指定时间及点击Notification消息之后的操作。例如以下代码:

AlarmManageralarmManager=(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方法。

publicstaticPendingIntentgetActivity(Contextcontext,intrequestCode,Intentintent,intflags,Bundleoptions){StringpackageName=context.getPackageName();StringresolvedType=intent!=null?intent.resolveTypeIfNeeded(context.getContentResolver()):null;try{intent.setAllowFds(false);IIntentSendertarget=ActivityManagerNative.getDefault().getIntentSender(ActivityManager.INTENT_SENDER_ACTIVITY,packageName,null,null,requestCode,newIntent[]{intent},resolvedType!=null?newString[]{resolvedType}:null,flags,options,UserHandle.myUserId());returntarget!=null?newPendingIntent(target):null;}catch(RemoteExceptione){}returnnull;}

从这个方法里面,我们发现,PendingIntent是跟Target有关,并且每次拿到的PendingIntent的内存地址都不是同一个,所以PendingIntent不是通过"=="运算来比较存在性的,我们找到PendingIntent的equals方法。

@Overridepublicbooleanequals(ObjectotherObj){if(otherObjinstanceofPendingIntent){returnmTarget.asBinder().equals(((PendingIntent)otherObj).mTarget.asBinder());}returnfalse;}

我们发现是比较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是否存在->如果不存在返回null

FLAG_CANCEL_CURRENT->target是否存在->如果存在则取消操作,重新生成一个target

FLAG_UPDATE_CURRENT->target是否存在->保持target,将intent的extras值更新

好了,以上是本人的一些浅见,希望对你有所帮助!