昨天帮朋友使用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是这样解释的:

Android之PendingIntent_Android

    这里我们主要介绍flags参数,这个参数比较重要,也较难理解。继续阅读API文档,文档告诉我们flags可能的值有如下几个:FLAG_ONE_SHOTFLAG_NO_CREATEFLAG_CANCEL_CURRENTFLAG_UPDATE_CURRENT

    现在我们分别来看看这几个值是什么意思:

Android之PendingIntent_PendingIntent_02

    这个参数的含义是:当做了启动Activity这件事情之后,后面再去做启动Activity这件事,都是无效的。

Android之PendingIntent_Android_03    

    这个参数的含义是:如果PendingIntent不存在,那么直接返回null而不创建。一般来说这个用的比较少。

Android之PendingIntent_AlarmManager_04

    这个参数的含义是:如果PendingIntent如果存在的话,那么首先取消它,然后再创建。

Android之PendingIntent_AlarmManager_05

    这个参数的含义是: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文档来看一下:

Android之PendingIntent_Android_06

    这里描述的是与operation、intent的action、data、categories等等有关。所以如果要让两个PendingIntent不同,可以通过设置intent的data参数:例如:intent2.setData(Uri.parse("task://12");同样你也可以改变其他值来让PendingIntent不同。

    再结合上面 FLAG_ONE_SHOTFLAG_NO_CREATEFLAG_CANCEL_CURRENTFLAG_UPDATE_CURRENT来理解一下。

  • FLAG_ONE_SHOT->target是否相同->如果相同则看send()方法是否调用->如果已经调用了,则不做任何操作。

  • FLAG_NO_CREATE->target是否存在->如果不存在返回null

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

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

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