Android之PendingIntent

    昨天幫朋友使用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是這樣解釋的:

wKioL1O7_inCH4icAAJW3An28lw237.jpg

    這裏我們主要介紹flags參數,這個參數比較重要,也較難理解。繼續閱讀API文檔,文檔告訴我們flags可能的值有如下幾個:FLAG_ONE_SHOTFLAG_NO_CREATEFLAG_CANCEL_CURRENTFLAG_UPDATE_CURRENT

    現在我們分別來看看這幾個值是什麼意思:

wKioL1O8AUPx5tkvAAEqmY3jAM4986.jpg

    這個參數的含義是:當做了啓動Activity這件事情之後,後面再去做啓動Activity這件事,都是無效的。

wKioL1O8ES3A7SKWAAEiOqm26Ks729.jpg    

    這個參數的含義是:如果PendingIntent不存在,那麼直接返回null而不創建。一般來說這個用的比較少。

wKioL1O8toKhBz49AAG_QjteYAM036.jpg

    這個參數的含義是:如果PendingIntent如果存在的話,那麼首先取消它,然後再創建。

wKiom1O8tzPBZbIJAAGrOnneOsg608.jpg

    這個參數的含義是: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文檔來看一下:

wKioL1O8xM6S6_Y5AAE_MidxL9Q032.jpg

    這裏描述的是與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值更新

    好了,以上是本人的一些淺見,希望對你有所幫助!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章