轉載!
Intent是一種運行時綁定(run-time binding)機制,它能在程式啟動並執行過程中串連兩個不同的組件。通過Intent,你的程式可以向Android表達某種請求或者意願,Android會根據意願的內容選擇適當的組件來完成請求。比如,有一個Activity希望開啟網頁瀏覽器查看某一網頁的內容,那麼這個Activity只需要發出WEB_SEARCH_ACTION請求給Android,Android會根據Intent的請求內容,查詢各組件註冊時聲明的IntentFilter,找到網頁瀏覽器Activity來瀏覽網頁。
Intent對象抽象地描述了要執行的操作,其描述的基本內容可以分為組件名稱、Action(動作)、Data(資料)、Category(類別)、Extra(附加資訊)和Flag(標誌位)6部分,下面是詳細的介紹。
(1) 組件名稱是指Intent目標組件的名稱。組件名稱是一個ComponentName對象,這種對象名稱是目標組件類名和目標組件所在應用程式的包名的組合。組件中包名不一定要和manifest檔案
中的包名完全符合。組件名稱是一個可選項。如果Intent訊息中指明了目標組件的名稱,這就是一個顯式訊息,Intent會傳遞給指明的組件。如果目標組件名稱並沒有指定,Android則通Intent
內的其他資訊和登入的IntentFilter的比較來選擇合適的目標組件。
(2) Action描述Intent所觸發動作名字的字串,對於Broadcast Intent來說,Action指被廣播出去的動作。理論上Action可以為任何字串,而與Android系統應用有關的Action字串以靜態字串常量的形式定義在了Intent類中。列出了當前Android系統中常見的Activity Action Intent的Action
- ACTION_CALL 撥出Data裡指定的電話號碼
- ACTION_EDIT 開啟編輯Data裡指定資料相對應的應用程式
- ACTION_MAIN 主程式入口,不會接收資料,結束後也不返回資料
- ACTION_SYNC 在Android平台和伺服器之間同步資料
- ACTION_VIEW 根據Data類型的不同,開啟相對應的應用程式以顯示資料
- ACTION_DIAL 啟動Dialer或其他撥號程式,並顯示Data裡指定的電話號碼
- ACTION_SENDTO 向Data裡描述的目標地址發送資料
- ACTION_TIME_TICK 系統時間每過一分鐘發出的廣播
- ACTION_TIME_CHANGED 系統時間通過設定發生了變化
- ACTION_TIMEZONE_CHANGED 時區改變
- ACTION_BOOT_COMPLETED 系統啟動完畢
- ACTION_PACKAGE_ADDED 新的應用程式apk包安裝完畢
- ACTION_PACKAGE_CHANGED 現有應用程式apk包改變
- ACTION_PACKAGE_REMOVED 現有應用程式apk包被刪除
- ACTION_UID_REMOVED 使用者id被刪除
(3) Data描述Intent要操作的資料URI和資料類型。有的動作需要對相應的資料進行處理。比如,對於動作ACTION_EDIT來說,它的資料可以為連絡人、簡訊息等可編輯的URI。而對於
ACTION_CALL來說,它的資料可以是一個tel://格式的電話號碼URI。正確設定Intent的資料對於Android尋找系統中匹配Intent請求的組件很重要。如果你使用了ACTION_CALL,但是你的資料卻設定成了mailto://格式的URI,那麼你所期望的“啟動打電話應用程式”這一動作會因為沒有與之相對應的應用程式而不會被執行。所以每次使用Intent時,我們都應該留意與設定的Action相關的資料類型和格式。
(4) Category是對被請求組件的額外描述資訊。Android也在Intent類中定義了一組靜態字串常量表示Intent不同的類別
(5) 列出了常用的Category常量
- CATEGORY_BROWSABLE 目標Activity能通過在網頁瀏覽器中點選連結而啟用(比如,點擊瀏覽器中的圖片連結)
- CATEGORY_GADGET 表示目標Activity可以被內嵌到其他Activity當中
- CATEGORY_HOME 目標Activity是HOME Activity,即手機開機啟動後顯示的Activity,或按下HOME鍵後顯示的Activity
- CATEGORY_LAUNCHER 表示目標Activity是應用程式中最優先被執行的Activity
- CATEGORY_PREFERENCE 表示目標Activity是一個喜好設定的Activity
(5) Extra當我們使用Intent串連不同的組件時,有時需要在Intent中附加額外的資訊,以便將資料傳遞給目標Activity。比如ACTION_TIMEZONE_CHANGED需要帶有附加資訊表示新的時區。Extra用索引值對結構儲存在Intent對象當中,Intent對象通過調用方法putExtras()和getExtras()來儲存和擷取Extra。Extra是以Bundle對象的形式來儲存的,Bundle對象提供了一系列put和get方法來設定、提取相應索引值資訊。在Intent類中同樣為Android系統應用的一些Action所附加資訊的索引值定義了靜態字串常量。
EXTRA_BCC 裝有郵件密送地址的字串數組
EXTRA_CC 裝有郵件抄送地址的字串數組
EXTRA_EMAIL 裝有郵件發送地址的字串數組
EXTRA_INTENT 使用ACTION_PICK_ACTIVITY動作時裝有Intent選項的Key
EXTRA_KEY_EVENT 觸發該Intent的按鍵的KeyEvent對象
EXTRA_PHONE_NUMBER 使用撥打到電話相關Action時,電話號碼字串的Key,類型為String
EXTRA_SHORTCUT_ICON 使用ACTION_CREATE_SHORTCUT在HomeActivity建立快
...
對於明確指出了目標組件名稱的Intent,我們稱之為“顯式Intent”。對於沒有明確指出目標組件名稱的Intent,則稱之為“隱式Intent”。Android系統使用Intent Filter 來尋找與隱Intent相關的對象.
顯式Intent直接用組件的名稱定義目標組件,這種方式很直接。但是由於開發人員往往並不清楚別的應用程式的組件名稱,因此,顯式Intent更多用於在應用程式內部傳遞訊息。比如在某
應用程式內,一個Activity啟動一個Service。隱式Intent恰恰相反,它不會用組件名稱定義需要啟用的目標組件,它更廣泛地用於在不同應用程式之間傳遞訊息。
清楚了顯式Intent和隱式Intent的概念後,我們再來看看決定Intent目標組件的因素。在顯式Intent訊息中,決定目標組件的唯一要素就是組件名稱,因此,如果你的Intent中已經明確定義了目標組件的名稱,那麼你就完全不用再定義其他Intent內容。而對於隱式Intent則不同,由於沒有明確的目標組件名稱,所以必須由Android系統輔助應用程式尋找與Intent請求意圖最匹配的組件。具體的選擇方法是:Android將Intent的請求內容和一個叫做Intent Filter的過濾器比較,Intent Filter中包含系統中所有可能的待選組件。如果Intent Filter中某一組件匹配隱式Intent請求的內容,那麼Android就選擇該組件作為該隱式Intent的目標組件.
Android 如何知道應用程式能夠處理某種類型的Intent 請求呢? 這需要應用程式在AndroidManifest.xml中聲明自己所含組件的過濾器(即可以匹配哪些Intent請求)。一個沒有聲
明Intent Filter的組件只能響應指明自己名字的顯式Intent請求,而無法響應隱式Intent請求。而一個聲明了Intent Filter的組件既可以響應顯式Intent請求,也可以響應隱式Intent請求。在通過和Intent Filter比較來解析隱式Intent請求時,Android將以下三個因素作為選擇的參考標準。
? Action
? Data
? Category
而Entra和Flag在解析收到Intent時是並不起作用的。
Intent Filter
應用程式的組件為了告訴Android自己能響應、處理哪些隱式Intent請求,可以聲明一個甚至多個Intent Filter。每個Intent Filter描述該組件所能響應Intent請求的能力——組件希望接收什麼類型的請求行為,什麼類型的請求資料。比如之前請求網頁瀏覽器這個例子中,網頁瀏覽器程式的Intent Filter就應該聲明它所希望接收的Intent Action是WEB_SEARCH_ACTION,以及與之相關的請求資料是網頁地址URI格式。
如何為組件聲明自己的Intent Filter? 常見的方法是在AndroidManifest.xml檔案中用屬性<Intent-Filter>描述組件的Intent Filter。
前面我們提到,隱式Intent和Intent Filter進行比較時的三要素是Intent的動作、資料以及類別。實際上,一個隱式Intent請求要能夠傳遞給目標組件,必要通過這三個方面的檢查。如果任何一方面不匹配,Android都不會將該隱式Intent傳遞給目標組件。接下來我們講解這三方面檢查的具體規則。
1.動作測試
<intent-filter>元素中可以包括子項目<action>,比如:
<intent-filter>
<action android:name="com.example.project.SHOW_CURRENT" />
<action android:name="com.example.project.SHOW_RECENT" />
<action android:name="com.example.project.SHOW_PENDING" />
</intent-filter>
一條<intent-filter>元素至少應該包含一個<action>,否則任何Intent請求都不能和該<intent-filter>匹配。
如果Intent請求的Action和<intent-filter>中個某一條<action>匹配,那麼該Intent就通過了這條<intent-filter>的動作測試。
如果Intent請求或<intent-filter>中沒有說明具體的Action類型,那麼會出現下面兩種情況。
(1) 如果<intent-filter>中沒有包含任何Action類型,那麼無論什麼Intent請求都無法和這條<intent-filter>匹配;
(2) 反之,如果Intent請求中沒有設定Action類型,那麼只要<intent-filter>中包含有Action類型,這個Intent請求就將順利地通過<intent-filter>的行為測試。
2.類別測試
<intent-filter>元素可以包含<category>子項目,比如:
<intent-filter . . . >
<category android:name="android.Intent.Category.DEFAULT" />
<category android:name="android.Intent.Category.BROWSABLE" />
</intent-filter>
只有當Intent請求中所有的Category與組件中某一個IntentFilter的<category>完全符合時,才會讓該Intent請求通過測試,IntentFilter中多餘的<category>聲明並不會導致匹配失敗。一個沒有指定任何類別測試的IntentFilter僅僅只會匹配沒有設定類別的Intent請求。
3.資料測試
資料在<intent-filter>中的描述如下:
<intent-filter . . . >
<data android:type="video/mpeg" android:scheme="http" . . . />
<data android:type="audio/mpeg" android:scheme="http" . . . />
</intent-filter>
<data>元素指定了希望接受的Intent請求的資料URI和資料類型,URI被分成三部分來進行匹配:scheme、authority和path。其中,用setData()設定的Inteat請求的URI資料類型和scheme必須與IntentFilter中所指定的一致。若IntentFilter中還指定了authority或path,它們也需要相匹配才會通過測試。
講解完Intent基本概念之後,接下來我們就使用Intent啟用Android內建的電話撥號程式,通過這個執行個體你會發現,使用Intent並不像其概念描述得那樣難。