前言:接上一篇廣播講后面的,intent
Intent
概述
Android中的Intent是一個類(就是一個封裝類許多方法的類薄货,不要想的那么神秘)翁都,可以用來在一個組件中啟動App中的另一個組件或者是啟動另一個App的組件,這里所說的組件指的是Activity谅猾、Service以及Broadcast柄慰。(這些組件不知道的,自行百度哈)
Intent的作用(其實就是intent這個類的功能)
?啟動Activity:可以將Intent對象傳遞給startActivity()方法或startActivityForResult()方法以啟動一個Activity税娜,該Intent對象包含了要啟動的Activity的信息及其他必要的數(shù)據(jù)坐搔。
回傳Activity的數(shù)據(jù):startActivityForResult和onactivityresult的配合使用,可以得到上一個activity中傳回的數(shù)據(jù)(后面詳細(xì)介紹)
?啟動Service:可以將Intent對象傳遞給startService()方法或bindService()方法以啟動一個Service敬矩,該Intent對象包含了要啟動的Service的信息及其他必要的數(shù)據(jù)概行。
?發(fā)送廣播:廣播是一種所有App都可以接收的信息。android系統(tǒng)會發(fā)布各種類型的廣播弧岳,比如發(fā)布開機(jī)廣播或手機(jī)充電廣播等凳忙。我們也可以給其他的App發(fā)送廣播,可以將Intent對象傳遞給sendBroadcast()方法或sendOrderedBroadcast()方法或sendStickyBroadcast()方法以發(fā)送自定義廣播禽炬。(如果不知道廣播涧卵,自行看上一篇)
Intent的類型
顯式的Intent:
如果Intent中明確包含了要啟動的組件的完整類名(包名及類名),那么這個Intent就是explict的腹尖,即顯式的柳恐。使用顯式Intent最典型的情形是在你自己的App中啟動一個組件,因為你自己肯定知道自己的要啟動的組件的類名热幔。比如乐设,為了響應(yīng)用戶操作通過顯式的Intent在你的App中啟動一個Activity或啟動一個Service下載文件。
當(dāng)創(chuàng)建了一個顯式Intent去啟動Activity或Service的時候断凶,系統(tǒng)會立即啟動Intent中所指定的組件伤提。
隱式的Intent:
如果Intent沒有包含要啟動的組件的完整類名,那么這個Intent就是implict的认烁,即隱式的肿男。雖然隱式的Intent沒有指定要啟動的組件的類名介汹,但是一般情況下,隱式的Intent都要指定需要執(zhí)行的action舶沛。一般嘹承,隱式的Intent只用在當(dāng)我們想在自己的App中通過Intent啟動另一個App的組件的時候,讓另一個App的組件接收并處理該Intent如庭。例如叹卷,你想在地圖上給用戶顯示一個位置,但是你的App又不支持地圖展示坪它,這時候你可以將位置信息放入到一個Intent中骤竹,然后給它指定相應(yīng)的action,通過這樣隱式的Intent請求其他的地圖型的App(例如Google Map往毡、百度地圖等)來在地圖中展示一個指定的位置蒙揣。隱式的Intent也體現(xiàn)了Android的一種設(shè)計哲學(xué):我自己的App無需包羅萬象所有功能,可以通過與其他App組合起來开瞭,給用戶提供很好的用戶體驗懒震。而連接自己的App與其他App的紐帶就是隱式Intent。(這點很重要嗤详,要學(xué)會用別人的資源為自己服務(wù))
當(dāng)創(chuàng)建了一個隱式Intent去使用的時候个扰,Android系統(tǒng)會將該隱式Intent所包含的信息與設(shè)備上其他所有App中manifest文件中注冊的組件的Intent Filters進(jìn)行對比過濾,從中找出滿足能夠接收處理該隱式Intent的App和對應(yīng)的組件葱色。如果有多個App中的某個組件都符合條件递宅,那么Android會彈出一個對話框讓用戶選擇需要啟動哪個App。(這里畫重點苍狰,有些同學(xué)可能還不知道吧)
Intent過濾器
Intent Filter恐锣,一個組件可以包含0個或多個Intent Filter。Intent Filter是寫在App的manifest文件中的舞痰,其通過設(shè)置action或uri數(shù)據(jù)類型等指明了組件能夠處理接收的Intent的類型土榴。如果你給你的Activity設(shè)置了Intent Filter,那么這就使得其他的App有可能通過隱式Intent啟動你的這個Activity响牛。反之玷禽,如果你的Activity不包含任何Intent Filter,那么該Activity只能通過顯式Intent啟動呀打,由于我們一般不會暴露出我們組件的完整類名矢赁,所以這種情況下,其他的App基本就不可能通過Intent啟動我們的Activity了(因為他們不知道該Activity的完整類名)贬丛,只能由我們自己的App通過顯式Intent啟動撩银。
注意:為了確保應(yīng)用的安全性,啟動service時豺憔,請始終使用顯式 Intent额获,且不要為服務(wù)聲明 Intent 過濾器够庙。使用隱式 Intent 啟動服務(wù)存在安全隱患,因為您無法確定哪些服務(wù)將響應(yīng) Intent抄邀,且用戶無法看到哪些服務(wù)已啟動耘眨。從 Android 5.0(API 級別 21)開始,如果使用隱式 Intent 調(diào)用bindService()境肾,系統(tǒng)會引發(fā)異常剔难。
前面都是基本介紹,下面奥喻,我們來詳細(xì)聊聊intent的構(gòu)建(當(dāng)然偶宫,這個構(gòu)建是比較完整的,這里是基本參考官方的)
Intent構(gòu)建(包含組成)
intent對象攜帶了 Android 系統(tǒng)用來確定要啟動哪個組件的信息(例如环鲤,準(zhǔn)確的組件名稱或應(yīng)當(dāng)接收該 Intent 的組件類別)读宙,以及收件人組件為了正確執(zhí)行操作而使用的信息(例如,要采取的操作以及要處理的數(shù)據(jù))楔绞。
intent中包含的主要信息如下:
組件名稱(Component Name)
要啟動的組件名稱。
這是可選項唇兑,但也是構(gòu)建顯式Intent 的一項重要信息酒朵,這意味著 Intent 應(yīng)當(dāng)僅傳遞給由組件名稱定義的應(yīng)用組件。 如果沒有組件名稱扎附,則 Intent 是隱式的蔫耽,且系統(tǒng)將根據(jù)其他 Intent 信息(例如,以下所述的操作留夜、數(shù)據(jù)和類別)決定哪個組件應(yīng)當(dāng)接收 Intent匙铡。 因此,如需在應(yīng)用中啟動特定的組件碍粥,則應(yīng)指定該組件的名稱鳖眼。
注:啟動Service時,您應(yīng)始終指定組件名稱嚼摩。 否則钦讳,您無法確定哪項服務(wù)會響應(yīng) Intent,且用戶無法看到哪項服務(wù)已啟動枕面。
Intetn的這一字段是一個ComponentName對象愿卒,您可以使用目標(biāo)組件的完全限定類名指定此對象,其中包括應(yīng)用的軟件包名稱潮秘。 例如琼开,com.example.ExampleActivity。您可以使用setComponent()枕荞、setClass()柜候、setClassName()或Intent構(gòu)造函數(shù)設(shè)置組件名稱搞动。
操作(?Action?)
指定要執(zhí)行的通用操作(例如樊零,“查看”或“選取”)的字符串铐殃。
對于廣播 Intent,這是指已發(fā)生且正在報告的操作疲吸。操作在很大程度上決定了其余 Intent 的構(gòu)成飞主,特別是數(shù)據(jù)和 extra 中包含的內(nèi)容狮惜。
您可以指定自己的操作,供 Intent 在您的應(yīng)用內(nèi)使用(或者供其他應(yīng)用在您的應(yīng)用中調(diào)用組件)碌识。但是碾篡,您通常應(yīng)該使用由Intent類或其他框架類定義的操作常量。以下是一些用于啟動 Activity 的常見操作:
ACTION_VIEW
如果您擁有一些某項 Activity 可向用戶顯示的信息(例如筏餐,要使用圖庫應(yīng)用查看的照片开泽;或者要使用地圖應(yīng)用查看的地址),請使用 Intent 將此操作與startActivity()結(jié)合使用魁瞪。
ACTIVITY_SEND
這也稱為“共享”Intent穆律。如果您擁有一些用戶可通過其他應(yīng)用(例如,電子郵件應(yīng)用或社交共享應(yīng)用)共享的數(shù)據(jù)导俘,則應(yīng)使用 Intent 將此操作與startActivity()結(jié)合使用峦耘。
有關(guān)更多定義通用操作的常量,請參閱類參考文檔旅薄。 其他操作在 Android 框架中的其他位置定義辅髓。例如,對于在系統(tǒng)的設(shè)置應(yīng)用中打開特定屏幕的操作少梁,將在Settings中定義洛口。
您可以使用setAction或Intent構(gòu)造函數(shù)為 Intent 指定操作。
如果定義自己的操作凯沪,請確保將應(yīng)用的軟件包名稱作為前綴第焰。 例如:
static final String ACTION_TIMETRAVEL="com.example.action.TIMETRAVEL";
注:提供一個intent? action大全參考地址 http://www.cnblogs.com/playing/archive/2010/09/15/1826918.html
數(shù)據(jù)(Data)
引用待操作數(shù)據(jù)和/或該數(shù)據(jù) MIME 類型的 URI(Uri對象)。提供的數(shù)據(jù)類型通常由 Intent 的操作決定妨马。例如樟遣,如果操作是ACTION_EDIT,則數(shù)據(jù)應(yīng)包含待編輯文檔的 URI身笤。
創(chuàng)建 Intent 時豹悬,除了指定 URI 以外,指定數(shù)據(jù)類型(其 MIME 類型)往往也很重要液荸。例如瞻佛,能夠顯示圖像的 Activity 可能無法播放音頻文件,即便 URI 格式十分類似時也是如此。因此伤柄,指定數(shù)據(jù)的 MIME 類型有助于 Android 系統(tǒng)找到接收 Intent 的最佳組件绊困。但有時,MIME 類型可以從 URI 中推斷得出适刀,特別當(dāng)數(shù)據(jù)是content:URI 時尤其如此秤朗。這表明數(shù)據(jù)位于設(shè)備中,且由ContentProvider控制笔喉,這使得數(shù)據(jù) MIME 類型對系統(tǒng)可見取视。
要僅設(shè)置數(shù)據(jù) URI,請調(diào)用setData()常挚。 要僅設(shè)置 MIME 類型作谭,請調(diào)用setType()。如有必要奄毡,您可以使用setDataAndType()同時顯式設(shè)置二者折欠。
注意:若要同時設(shè)置 URI 和 MIME 類型,請勿調(diào)用setData()和setType()吼过,因為它們會互相抵消彼此的值锐秦。請始終使用setDataAndType()同時設(shè)置 URI 和 MIME 類型。
類別( Category )
一個包含應(yīng)處理 Intent 組件類型的附加信息的字符串盗忱。 您可以將任意數(shù)量的類別描述放入一個 Intent 中酱床,但大多數(shù) Intent 均不需要類別。 以下是一些常見類別:
CATEGORY_BROWSABLE
目標(biāo) Activity 允許本身通過網(wǎng)絡(luò)瀏覽器啟動售淡,以顯示鏈接引用的數(shù)據(jù),如圖像或電子郵件慷垮。
CATEGORY_LAUNCHER
該 Activity 是任務(wù)的初始 Activity揖闸,在系統(tǒng)的應(yīng)用啟動器中列出。
有關(guān)類別的完整列表料身,百度吧
您可以使用addCategory()指定類別汤纸。
以上列出的這些屬性(組件名稱、操作芹血、數(shù)據(jù)和類別)表示 Intent 的既定特征贮泞。 通過讀取這些屬性,Android 系統(tǒng)能夠解析應(yīng)當(dāng)啟動哪個應(yīng)用組件幔烛。
Extra( 筆記拿出來了啃擦,重點 ,用心看)
或許就這么看饿悬,不知道是什么但是令蛉,你是否記得 intent.putExtra(key,value)呢?沒錯,這個Extra就是我們常用的那個東西珠叔。
extras蝎宇,顧名思義,就是額外的數(shù)據(jù)信息祷安,Intent中有一個Bundle對象存儲著各種鍵值對姥芥,接收該Intent的組件可以從中讀取出所需要的信息以便完成相應(yīng)的工作。有的Intent需要靠Uri攜帶數(shù)據(jù)汇鞭,有的Intent是靠extras攜帶數(shù)據(jù)信息凉唐。
你可以通過調(diào)用Intent對象的各種重載的putExtra(key, value)方法向Intent中加入各種鍵值對形式的額外數(shù)據(jù)。你也可以直接創(chuàng)建一個Bundle對象虱咧,向該Bundle對象傳入很多鍵值對熊榛,然后通過調(diào)用Intent對象的putExtras(Bundle)方法將其一塊設(shè)置給Intent對象中去。
例如腕巡,你創(chuàng)建了一個action為ACTION_SEND的Intent對象玄坦,然后想用它啟動e-mail發(fā)送郵件,那么你需要給該Intent對象設(shè)置兩個extra的值:
用Intent.EXTRA_EMAIL作為key值設(shè)置收件方绘沉,用Intent.EXTRA_SUBJECT作為key值設(shè)置郵件標(biāo)題煎楣。
Intent類里面也指定了很多預(yù)定義的EXTRA_*形式的extra,例如上面我們提到的(Intent.EXTRA_EMAIL和Intent.EXTRA_SUBJECT)车伞。如果你想要聲明你自己自定義的extra择懂,請確保將你的App的包名作為你的extra的前綴,例如:
static final String EXTRA_GIGAWATTS ="com.example.EXTRA_GIGAWATTS";
標(biāo)志(Flags)
flag就是標(biāo)記的意思另玖,Intent類中定義的flag能夠起到作為Intent對象的元數(shù)據(jù)的作用困曙。這些flag會告知Android系統(tǒng)如何啟動Activity(例如,新啟動的Activity屬于哪個task)以及在該Activity啟動后如何對待它谦去。Flags大全慷丽,也請自行百度,就不寫了鳄哭。
本來想寫一些例子的要糊,不過想了一下,我的重點不在那上面就不寫了(想了解的同學(xué)妆丘,自行百度锄俄,隱式intent,顯式intent)
強(qiáng)制用戶使用App Chooser
如果有多個應(yīng)用響應(yīng)隱式 Intent勺拣,則用戶可以選擇要使用的應(yīng)用奶赠,并將其設(shè)置為該操作的默認(rèn)選項。 如果用戶可能希望今后一直使用相同的應(yīng)用執(zhí)行某項操作(例如药有,打開網(wǎng)頁時车柠,用戶往往傾向于僅使用一種網(wǎng)絡(luò)瀏覽器),則這一點十分有用。
但是竹祷,如果多個應(yīng)用可以響應(yīng) Intent谈跛,且用戶可能希望每次使用不同的應(yīng)用,則應(yīng)采用顯式方式顯示選擇器對話框塑陵。 選擇器對話框每次都會要求用戶選擇用于操作的應(yīng)用(用戶無法為該操作選擇默認(rèn)應(yīng)用)感憾。 例如,當(dāng)應(yīng)用使用ACTION_SEND操作執(zhí)行“共享”時令花,用戶根據(jù)目前的狀況可能需要使用另一不同的應(yīng)用阻桅,因此應(yīng)當(dāng)始終使用選擇器對話框。
要顯示選擇器兼都,請使用createChooser()創(chuàng)建Intent嫂沉,并將其傳遞給startActivity()。例如:
其實扮碧,本來還想聊聊自己app添加條件趟章,接收外部app調(diào)用的東西,不過慎王,后來發(fā)現(xiàn)蚓土,這一部分,除非自己做到像某Q或者某地圖那樣赖淤,不然蜀漆,根本就沒人來調(diào)用你。所以咱旱,就不寫了确丢,需要了解的,自行百度:接收intent調(diào)用自己app
順便總結(jié)一下啊 intent-filter其實吐限,就是action category data的組合鲜侥,這里就不深入了,畢竟這是基礎(chǔ)技術(shù)篇毯盈,屬于基礎(chǔ)部分剃毒。
下面我們再介紹病袄,intent中比較特殊的一個東西搂赋,penddingIntent
penddingIntent(這部分,屬于額外部分益缠,平時使用的頻率相對較少)
概述
在Android中脑奠,我們常常使用PendingIntent來表達(dá)一種“留待日后處理”的意思。從這個角度來說幅慌,PendingIntent可以被理解為一種特殊的異步處理機(jī)制宋欺。不過,單就命名而言,PendingIntent其實具有一定誤導(dǎo)性齿诞,因為它既不繼承于Intent酸休,也不包含Intent,它的核心可以粗略地匯總成四個字——“異步激發(fā)”祷杈。
很明顯斑司,這種異步激發(fā)常常是要跨進(jìn)程執(zhí)行的。比如說A進(jìn)程作為發(fā)起端但汞,它可以從系統(tǒng)“獲取”一個PendingIntent宿刮,然后A進(jìn)程可以將PendingIntent對象通過binder機(jī)制“傳遞”給B進(jìn)程,再由B進(jìn)程在未來某個合適時機(jī)私蕾,“回調(diào)”PendingIntent對象的send()動作僵缺,完成激發(fā)。
在Android系統(tǒng)中踩叭,最適合做集中性管理的組件就是AMS(Activity Manager Service)啦磕潮,所以它義不容辭地承擔(dān)起管理所有PendingIntent的職責(zé)。這樣我們就可以畫出如下示意圖:
注意其中的第4步“遞送相應(yīng)的intent”懊纳。這一步遞送的intent是從何而來的呢揉抵?簡單地說,當(dāng)發(fā)起端獲取PendingIntent時嗤疯,其實是需要同時提供若干intent的冤今。這些intent和PendingIntent只是配套的關(guān)系,而不是聚合的關(guān)系茂缚,它們會被緩存在AMS中戏罢。日后,一旦處理端將PendingIntent的“激發(fā)”語義傳遞到AMS脚囊,AMS就會嘗試找到與這個PendingIntent對應(yīng)的若干intent龟糕,并遞送出去。
當(dāng)然悔耘,以上說的只是大概情況讲岁,實際的技術(shù)細(xì)節(jié)會更復(fù)雜一點兒。下面我們就來談?wù)劶?xì)節(jié)衬以。
PendingIntent的技術(shù)細(xì)節(jié)
發(fā)起端獲取PendingIntent
我們先要理解缓艳,所謂的“發(fā)起端獲取PendingIntent”到底指的是什么。難道只是簡單new一個PendingIntent對象嗎看峻?當(dāng)然不是阶淘。此處的“獲取”動作其實還含有向AMS“注冊”intent的語義。
在PendingIntent.java文件中互妓,我們可以看到有如下幾個比較常見的靜態(tài)函數(shù):
public static PendingIntentgetActivity(Context context, int requestCode, Intent intent, int flags)
public static PendingIntentgetActivities(Context context, int requestCode, Intent[] intents, int flags)
public static PendingIntentgetActivities(Context context, int requestCode, Intent[] intents, int flags, Bundle options)
public static PendingIntentgetBroadcast(Context context, int requestCode, Intent intent, int flags)
public static PendingIntentgetService(Context context, int requestCode, Intent intent, int flags)
通過這些名字溪窒,大致猜猜想坤塞,就是從activity,broadcast澈蚌,service中獲取的摹芙,這樣想是不是邏輯很通呀,但是宛瞄,說實話瘫辩,這幾個函數(shù)的命名可真不怎么樣,所以我們簡單解釋一下坛悉。上面的getActivity()的意思其實是伐厌,獲取一個PendingIntent對象,而且該對象日后激發(fā)時所做的事情是啟動一個新activity裸影。也就是說挣轨,當(dāng)它異步激發(fā)時,會執(zhí)行類似Context.startActivity()那樣的動作轩猩。相應(yīng)地卷扮,getBroadcast()和getService()所獲取的PendingIntent對象在激發(fā)時,會分別執(zhí)行類似Context..sendBroadcast()和Context.startService()這樣的動作均践。至于最后兩個getActivities()晤锹,用得比較少,激發(fā)時可以啟動幾個activity彤委。
怎么樣鞭铆,是不是感覺,被坑了焦影,也不知道誰取得名字车遂,誤導(dǎo)性這么強(qiáng)。下面舉個簡單例子:
其中那句new PendingIntent(target)創(chuàng)建了PendingIntent對象斯辰,其重要性自不待言舶担。然而,這個對象的內(nèi)部核心其實是由上面那個getIntentSender()函數(shù)得來的彬呻。而這個IIntentSender核心才是我們真正需要關(guān)心的東西衣陶。
說穿了,此處的IIntentSender對象是個binder代理闸氮,它對應(yīng)的binder實體是AMS中的PendingIntentRecord對象剪况。PendingIntent對象構(gòu)造之時,IIntentSender代理作為參數(shù)傳進(jìn)來湖苞,并記錄在PendingIntent的mTarget域拯欧。日后详囤,當(dāng)PendingIntent執(zhí)行異步激發(fā)時财骨,其內(nèi)部就是靠這個mTarget域向AMS傳遞語義的镐作。(這里可能有點難懂,簡單說隆箩,就是獲取一個標(biāo)識该贾,以后,激發(fā)的時候捌臊,通過這個標(biāo)識杨蛋,去激發(fā)對應(yīng)的事件)
我們前文說過,PendingIntent常常會經(jīng)由binder機(jī)制理澎,傳遞到另一個進(jìn)程去逞力。而binder機(jī)制可以保證,目標(biāo)進(jìn)程得到的PendingIntent的mTarget域也是合法的IIntentSender代理糠爬,而且和發(fā)起端的IIntentSender代理對應(yīng)著同一個PendingIntentRecord實體寇荧。示意圖如下:
看到這個圖,你知道了mTarget执隧,但是揩抡,這里面有一個PendingIntentRecord,這是什么鬼镀琉?別急峦嗤,下面就講
AMS里的PendingIntentRecord
注意其中那個key域。這里的Key是個PendingIntentRecord的內(nèi)嵌類
注意其中的allIntents[]數(shù)組域以及requestIntent域屋摔。前者記錄了當(dāng)初獲取PendingIntent時烁设,用戶所指定的所有intent(雖然一般情況下只會指定一個intent,但類似getActivities()這樣的函數(shù)還是可以指定多個intent的)钓试,而后者可以粗淺地理解為用戶所指定的那個intent數(shù)組中的最后一個intent∈鹩龋現(xiàn)在大家應(yīng)該清楚異步激發(fā)時用到的intent都存在哪里了吧。
我們再來看看Key的構(gòu)造函數(shù)亚侠,是怎樣吧
Key不光承擔(dān)著記錄信息的作用曹体,它還承擔(dān)“鍵值”的作用。這是不是和我們平時理解的key不一樣硝烂。其實箕别,不用多想,這就是一個類罷了
在AMS中滞谢,管理著系統(tǒng)中所有的PendingIntentRecord節(jié)點串稀,所以需要把這些節(jié)點組織成一張表(嗯,可能有些同學(xué)不知道什么叫節(jié)點狮杨,也不明白為什么這里會事一張表母截,沒關(guān)系,黑盒思想橄教,不用知道清寇,因為這部分東西涉及偏底層了喘漏,先就這樣吧)
AMS中的PendingIntentRecord總表
這張哈希映射表的鍵值類型就是剛才所說的PendingIntentRecord.Key。
以后每當(dāng)我們要獲取PendingIntent對象時华烟,PendingIntent里的mTarget是這樣得到的:AMS會先查mIntentSenderRecords表翩迈,如果能找到符合的PendingIntentRecord節(jié)點,則返回之盔夜。如果找不到负饲,就創(chuàng)建一個新的PendingIntentRecord節(jié)點。因為PendingIntentRecord是個binder實體喂链,所以經(jīng)過binder機(jī)制傳遞后返十,客戶進(jìn)程拿到的就是個合法的binder代理。如此一來椭微,前文的示意圖可以進(jìn)一步修改成下圖:
AMS里的getIntentSender()函數(shù)
現(xiàn)在吧慢,我們回過頭繼續(xù)說前文的getActivity(),以及其調(diào)用的getIntentSender()赏表。我們先列一遍getActivity()的原型:
context參數(shù)是調(diào)用方的上下文检诗。
requestCode是個簡單的整數(shù),起區(qū)分作用瓢剿。
intent是異步激發(fā)時將發(fā)出的intent逢慌。
flags可以包含一些既有的標(biāo)識,比如FLAG_ONE_SHOT间狂、FLAG_NO_CREATE攻泼、FLAG_CANCEL_CURRENT、FLAG_UPDATE_CURRENT等等鉴象。(不少同學(xué)對這個域不是很清楚忙菠,沒關(guān)系,黑盒思想)
options可以攜帶一些額外的數(shù)據(jù)纺弊。
getActivity()的代碼很簡單牛欢,其參數(shù)基本上都傳給了getIntentSender()。
getIntentSender()的原型大體是這樣的:
其參數(shù)比getActivity()要多一些淆游,我們逐個說明
type參數(shù)表明PendingIntent的類型?getActivity()和getActivities()動作里指定的類型值是INTENT_SENDER_ACTIVITY傍睹,getBroadcast()和getService()和動作里指定的類型值分別是INTENT_SENDER_BROADCAST和INTENT_SENDER_SERVICE。另外犹菱,在Activity.java文件中拾稳,我們還看到一個createPendingResult()函數(shù),這個函數(shù)表達(dá)了發(fā)起方的activity日后希望得到result回饋的意思腊脱,所以其內(nèi)部調(diào)用getIntentSender()時指定的類型值為INTENT_SENDER_ACTIVITY_RESULT访得。
packageName參數(shù)表示發(fā)起端所屬的包名。
token參數(shù)是個指代回饋目標(biāo)方的代理陕凹。
這是什么意思呢悍抑?我們常用的getActivity()鳄炉、getBroadcast()和getService()中,只是把這個參數(shù)簡單地指定為null传趾,表示這個PendingIntent激發(fā)時,是不需要發(fā)回什么回饋的泥技。不過當(dāng)我們希望獲取類型為INTENT_SENDER_ACTIVITY_RESULT的PendingIntent時浆兰,就需要指定token參數(shù)了。具體可參考createPendingResult()的代碼:
看到了嗎珊豹?傳入的token為Activity的mToken或者其mParent.mToken簸呈。說得簡單點兒,AMS內(nèi)部可以根據(jù)這個token找到其對應(yīng)的ActivityRecord店茶,日后當(dāng)PendingIntent激發(fā)時蜕便,AMS可以根據(jù)這個ActivityRecord確定出該向哪個目標(biāo)進(jìn)程的哪個Activity發(fā)出result語義。
resultWho參數(shù)和token參數(shù)息息相關(guān)贩幻,一般也是null啦轿腺。在createPendingResult()中,其值為Activity的mEmbeddedID字符串丛楚。
requestCode參數(shù)是個簡單的整數(shù)族壳,可以在獲取PendingIntent時由用戶指定,它可以起區(qū)分的作用趣些。
intents數(shù)組參數(shù)是異步激發(fā)時希望發(fā)出的intent仿荆。對于getActivity()、getBroadcast()和getService()來說坏平,都只會指定一個intent而已拢操。只有g(shù)etActivities()會嘗試一次傳入若干intent。
resolvedTypes參數(shù)基本上和intent是相關(guān)的舶替。一般是這樣得到的:
這個值常常和intent內(nèi)部的mData URI有關(guān)系令境,比如最終的值可能是URI對應(yīng)的MIME類型。
flags參數(shù)可以指定PendingIntent的一些行為特點顾瞪。具體了解展父,百度吧。
還有一些底層實現(xiàn)玲昧,這里就不詳細(xì)說了栖茉,下面,就說說關(guān)于激發(fā)的事情孵延。
PendingIntent的激發(fā)動作
下面我們來看PendingIntent的激發(fā)動作吕漂。在前文我們已經(jīng)說過,當(dāng)需要激發(fā)PendingIntent之時尘应,主要是通過調(diào)用PendingIntent的send()函數(shù)來完成激發(fā)動作的惶凝。PendingIntent提供了多個形式的send()函數(shù)吼虎,然而這些函數(shù)的內(nèi)部其實調(diào)用的是同一個send(),其函數(shù)原型如下:
該函數(shù)內(nèi)部最關(guān)鍵的一句是:
我們前文已經(jīng)介紹過這個mTarget域了苍鲜,它對應(yīng)著AMS中的某個PendingIntentRecord思灰。
所以我們要看一下PendingIntentRecord一側(cè)的send()函數(shù),其代碼如下:
其中sendInner()才是真正做激發(fā)動作的函數(shù)混滔。
sendInner()完成的主要邏輯動作有:
1 如果當(dāng)前PendingIntentRecord節(jié)點已經(jīng)處于canceled域為true的狀態(tài)洒疚,那么說明這個節(jié)點已經(jīng)被取消掉了,此時sendInner()不會做任何實質(zhì)上的激發(fā)動作坯屿,只是簡單地return ActivityManager.START_CANCELED而已油湖。
2 如果當(dāng)初在創(chuàng)建這個節(jié)點時,使用者已經(jīng)指定了FLAG_ONE_SHOT標(biāo)志位的話领跛,那么此時sendInner()會把這個PendingIntentRecord節(jié)點從AMS中的總表中摘除乏德,并且把canceled域設(shè)為true。而后的操作和普通激發(fā)時的動作是一致的吠昭,也就是說也會走下面的第3)步喊括。
3 關(guān)于普通激發(fā)時應(yīng)執(zhí)行的邏輯動作是,根據(jù)當(dāng)初創(chuàng)建PendingIntentRecord節(jié)點時矢棚,用戶指定的type類型瘾晃,進(jìn)行不同的處理。這個type其實就是我們前文所說的INTENT_SENDER_ACTIVITY幻妓、INTENT_SENDER_BROADCAST蹦误、INTENT_SENDER_SERVICE等類型啦,大家如有興趣肉津,可自己參考本文一開始所說的getActivity()强胰、getBroadcast()、getService()等函數(shù)的實現(xiàn)代碼妹沙。
理論說一大堆偶洋,下面還是用一個例子說明一下吧:
這個例子是我們常見的一個例子,就是通知距糖。點擊通知欄玄窝,然后,就會跳轉(zhuǎn)到對應(yīng)activity:
這樣寫就可以了悍引,然后恩脂,在通知欄那里點擊通知,ok趣斤,跳轉(zhuǎn)到對應(yīng)地方俩块,是不是非常簡單。當(dāng)然,這里只是簡單舉個例子玉凯,不過势腮,目前而言,我們用到的也不會太多漫仆。
總結(jié)一下捎拯,pendingintent,其實盲厌,就是不馬上執(zhí)行罷了署照,相當(dāng)于,一個觸發(fā)器狸眼,等什么時候藤树,觸發(fā)了某個條件浴滴,就去執(zhí)行拓萌。簡單來說,這玩意用法就是
1.包裝intent(意圖升略,目的)
2.pendingintent裝載前面的intent(當(dāng)然要配置一些屬性微王,比如context呀之類的)
3.等待觸發(fā)(AMS做的事情,我們不管)
4.觸發(fā)(比如點擊事件之類的)
最后要提一個東西品嚣,曾經(jīng)遇到的坑
沒錯就是這個方法炕倘,當(dāng)接收數(shù)據(jù)的activity已經(jīng)存在與棧中的時候,我們常規(guī)的getIntent,是得不到新過來的intent的翰撑,需要罩旋,用上面這個方法,才能獲取到新的intent眶诈。這只是一個小插曲涨醋,不過,這個問題逝撬,還是需要記住的浴骂。