徹底認識 PendingIntent

最近在寫一個鬧鐘程序的時候使用到了 PendingIntent, 而且是兩個地方用到,一個是 AlarmManager 定時的時候, 另一個是在點擊通知進入應用的時候。其實我早就想深入研究一下 PendingIntent 了,因爲我很好奇一下幾個問題:

  1. 已經有了 Intent, 爲什麼還有 PendingIntent?
  2. PendingIntent 也就幾個場景用到過,還有其他場景嗎?
  3. 它的內部實現。

Intent 和 PendingIntent 的區別

Intent

Intent 是意圖的意思。Android 中的 Intent 正是取自這個意思,它是一個消息對象,通過它,Android 系統的四大組件能夠方便的通信,並且保證解耦。

Intent 可以說明某種意圖,攜帶一種行爲和相應的數據,發送到目標組件。

IntentFilter 與 Intent 配套使用,它聲明瞭一個組件接受某個 Intent。

PendingIntent

PendingIntent 是對 Intent 的封裝,關鍵的不同在於:

A組件 創建了一個 PendingIntent 的對象然後傳給 B組件,B 在執行這個 PendingIntent 的 send 時候,它裏面的 Intent 會被髮送出去,而接受到這個 Intent 的 C 組件會認爲是 A 發的。

B 以 A 的權限和身份發送了這個 Intent。

比如,我們的 Activity 如果設置了 exported = false,其他應用如果使用 Intent 就訪問不到這個 Activity,但是使用 PendingIntent 是可以的。

綜上所述,PendingIntent 有兩個特點:

  1. 將某個動作的觸發時機交給其他應用
  2. 讓那個應用代表自己去執行那個動作(權限都給他了)

API

獲取 PendingIntent

  1. getActivity
  2. getActivities
  3. getBroadcast
  4. getService
  5. getForegroundService

爲什麼沒有 getContentProvider?
我猜測,ContentProvider 作爲一個數據源,太重要了,相當於是把數據直接暴露出去了

它們的參數都相同,都是四個:Context, requestCode, Intent, flags。Context 不必多說,要想讓其他組件代替自己辦事,當然要將自己的上下文傳給它。action, requestCode 和 Intent 共同來標誌一個行爲的唯一性,什麼意思呢?

簡單的說,我們通過相同的方法(action), 相同的 requestCode 和相同的 Intent 獲取到的 PendingIntent, 雖然可能不是同一個對象,但是,卻是代表同一個東西,之所以這樣看 flags 參數就知道了。

FLAG_ONE_SHOT: 只執行一次, 在調用了 send 以後自動調用 cancel,不能在調用 send 了。
FLAG_NO_CREATE: 不創建新的,如果我們之前設置過,這次就能獲取到,否則,返回 null。
FLAG_CANCEL_CURRENT: 如果之前設置過,就取消掉, 重新創建個新的
FLAG_UPDATE_CURRENT: 如果之前設置過,就更新它。更新什麼呢,Intent 的 Extras
FLAG_IMMUTABLE: 設置 Intent 在 send 的時候不能更改

發送 PendingIntent

send 是觸發 PendingIntent 包含的行爲,它有很多重載形式,我們通常的開發用不到他,除非我們做桌面程序開發或者 Android Framework 開發。
這裏我們只是大體說明一下,可以傳給它一個 Intent 來對它原來的 Intent 做修改,但是如果目標設置了 FLAG_IMMUTABLE 則給參數忽略。可以設置 callback 當發送完成獲得回調,並且可以通過設置handler決定回調發生的線程。

取消 PendingIntent

只有設置 PendingIntent 的原來的應用可以取消它,發送方只能發送,當一個 PendingIntent 被取消後,發送則不會成功。

PendingIntent 的使用場景

已知的使用場景是:

  1. 通知,在點擊通知時執行調起本應用的操作,當然也可以執行其他操作
  2. 鬧鐘,定時執行某個操作
  3. 桌面小部件,點擊小部件時執行某個操作

通知,鬧鐘,桌面小部件,都是運行在其他應用中的,但是給我們的感知就像是我們自己的應用的一部分。

內部實現

大體的原理是: A應用希望讓B應用幫忙觸發一個行爲,這是跨應用的通信,需要 Android 系統作爲中間人,這裏的中間人就是 ActivityManager。 A應用創建建 PendingIntent,在創建 PendingIntent 的過程中,向 ActivityManager 註冊了這個 PendingIntent,所以,即使A應用死了,當它再次甦醒時,只要提供相同的參數,還是可以獲取到之前那個 PendingIntent 的。當 A 將 PendingIntent 調用系統 API 比如 AlarmManager.set(),實際是將權限給了B應用,這時候, B應用可以根據參數信息,來從 ActivityManager 獲取到 A 設置的 PendingIntent。


匹配 PendingIntent 相同時,需要匹配 Intent 相同,Intent 如何匹配相同的?

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