在一個Android應用中,主要是由四種組件組成的,這四種組件可參考「Android應用的構成」。
而這四種組件是獨立的,它們之間能夠互相調用,協調工做,最終組成一個真正的Android應用。
在這些組件之間的通信中,主要是由Intent協助完成的。
Intent負責對應用中一次操做的動做、動做涉及數據、附加數據進行描述,Android則根據此Intent的描述,負責找到對應的組件,將 Intent傳遞給調用的組件,並完成組件的調用。
所以,Intent在這裏起着一個媒體中介的做用,專門提供組件互相調用的相關信息,實現調用者與被調用者之間的解耦。
例如,在一個聯繫人維護的應用中,當咱們在一個聯繫人列表屏幕(假設對應的Activity爲listActivity)上,點擊某個聯繫人後,但願可以跳出此聯繫人的詳細信息屏幕(假設對應的Activity爲detailActivity)
爲了實現這個目的,listActivity須要構造一個 Intent,這個Intent用於告訴系統,咱們要作「查看」動做,此動做對應的查看對象是「某聯繫人」,而後調用startActivity (Intent intent),
將構造的Intent傳入,系統會根據此Intent中的描述,到ManiFest中找到知足此Intent要求的Activity,系統會調用找到的 Activity,即爲detailActivity,最終傳入Intent,detailActivity則會根據此Intent中的描述,執行相應的操做。
1、抽象描述要描述什麼
在Android參考文檔中,對Intent的定義是執行某操做的一個抽象描述(確實很抽象)。咱們先來看看這裏的抽象描述,到底描述了什麼。
首先,是要執行的動做(action)的一個簡要描述,如VIEW_ACTION(查看)、EDIT_ACTION(修改)等,Android爲咱們定義了一套標準動做:
MAIN_ACTION
VIEW_ACTION
EDIT_ACTION
PICK_ACTION
GET_CONTENT_ACTION
DIAL_ACTION
CALL_ACTION
SENDTO_ACTION
ANSWER_ACTION
INSERT_ACTION
DELETE_ACTION
RUN_ACTION
LOGIN_ACTION
CLEAR_CREDENTIALS_ACTION
SYNC_ACTION
PICK_ACTIVITY_ACTION
WEB_SEARCH_ACTION
此外,咱們還能夠根據應用的須要,定義咱們本身的動做,並可定義相應的Activity來處理咱們的自定義動做。
其次,是執行動做要操做的數據(data),Android中採用指向數據的一個URI來表示,如在聯繫人應用中,一個指向某聯繫人的URI可能爲:content://contacts/1。
這種URI表示,經過 ContentURI這個類來描述,具體能夠參考android.net.ContentURI類的文檔。
以聯繫人應用爲例,如下是一些action / data對,及其它們要表達的意圖:
VIEW_ACTION content://contacts/1-- 顯示標識符爲"1"的聯繫人的詳細信息
EDIT_ACTION content://contacts/1-- 編輯標識符爲"1"的聯繫人的詳細信息
VIEW_ACTION content://contacts/-- 顯示全部聯繫人的列表
PICK_ACTION content://contacts/-- 顯示全部聯繫人的列表,而且容許用戶在列表中選擇一個聯繫人,而後把這個聯繫人返回給父activity。例如:電子郵件客戶端可使用這個Intent,要求用戶在聯繫人列表中選擇一個聯繫人
另外,除了action和data這兩個重要屬性外,還有一些附加屬性:
category(類別),被執行動做的附加信息。例如 LAUNCHER_CATEGORY 表示Intent 的接受者應該在Launcher中做爲頂級應用出現;而ALTERNATIVE_CATEGORY表示當前的Intent是一系列的可選動做中的一個,這些動做能夠在同一塊數據上執行。
type(數據類型),顯式指定Intent的數據類型(MIME)。通常Intent的數據類型可以根據數據自己進行斷定,可是經過設置這個屬性,能夠強制採用顯式指定的類型而再也不進行推導。
component(組件),指定Intent的的目標組件的類名稱。一般 Android會根據Intent 中包含的其它屬性的信息,好比action、data/type、category進行查找,最終找到一個與之匹配的目標組件。可是,若是 component這個屬性有指定的話,將直接使用它指定的組件,而再也不執行上述查找過程。指定了這個屬性之後,Intent的其它全部屬性都是可選的。
extras(附加信息),是其它全部附加信息的集合。使用extras能夠爲組件提供擴展信息,好比,若是要執行「發送電子郵件」這個動做,能夠將電子郵件的標題、正文等保存在extras裏,傳給電子郵件發送組件。
總之,action、 data/type、category和extras 一塊兒造成了一種語言。
這種語言使系統可以理解諸如「查看某聯繫人的詳細信息」之類的短語。
隨着應用不斷的加入到系統中,它們能夠添加新的action、 data/type、category來擴展這種語言。
應用也能夠提供本身的Activity來處理已經存在的這樣的「短語」,從而改變這些「短語」的行爲。
2、Android如何解析Intent
在應用中,咱們能夠以兩種形式來使用Intent:
直接Intent:指定了component屬性的Intent(調用setComponent(ComponentName)或者setClass(Context, Class)來指定)。經過指定具體的組件類,通知應用啓動對應的組件。
間接Intent:沒有指定comonent屬性的Intent。這些Intent須要包含足夠的信息,這樣系統才能根據這些信息,在在全部的可用組件中,肯定知足此Intent的組件。
對於直接Intent,Android不須要去作解析,由於目標組件已經很明確,Android須要解析的是那些間接Intent,經過解析,將 Intent映射給能夠處理此Intent的Activity、IntentReceiver或Service。
Intent解析機制主要是經過查找已註冊在AndroidManifest.xml中的全部IntentFilter及其中定義的Intent,最終找到匹配的Intent。在這個解析過程當中,Android是經過Intent的action、type、category這三個屬性來進行判斷的,判斷方法以下:
若是Intent指明定了action,則目標組件的IntentFilter的action列表中就必須包含有這個action,不然不能匹配;
若是Intent沒有提供type,系統將從data中獲得數據類型。和action同樣,目標組件的數據類型列表中必須包含Intent的數據類型,不然不能匹配。
若是Intent中的數據不是content: 類型的URI,並且Intent也沒有明確指定它的type,將根據Intent中數據的scheme (好比 http: 或者mailto: ) 進行匹配。同上,Intent 的scheme必須出如今目標組件的scheme列表中。
若是Intent指定了一個或多個category,這些類別必須所有出如今組建的類別列表中。好比Intent中包含了兩個類別:LAUNCHER_CATEGORY 和 ALTERNATIVE_CATEGORY,解析獲得的目標組件必須至少包含這兩個類別。
3、應用例子
如下,以Android SDK中的便箋例子來講明,Intent如何定義及如何被解析。這個應用可讓用戶瀏覽便箋列表、查看每個便箋的詳細信息。
android
複製代碼
例子中的第一個Activity是com.google.android.notepad.NotesList,它是應用的主入口,提供了三個功能,分別由三個 intent-filter進行描述:
一、第一個是進入便箋應用的頂級入口(action爲android.app.action.MAIN)。類型爲android.app.category.LAUNCHER代表這個Activity將在Launcher中列出。
二、第二個是,當type爲vnd.android.cursor.dir/vnd.google.note(保存便箋記錄的目錄)時,能夠查看可用的便箋(action爲android.app.action.VIEW),或者讓用戶選擇一個便箋並返回給調用者(action爲 android.app.action.PICK)。
三、第三個是,當type爲vnd.android.cursor.item/vnd.google.note時,返回給調用者一個用戶選擇的便箋(action爲android.app.action.GET_CONTENT),而用戶卻不須要知道便箋從哪裏讀取的。有了這些功能,下面的 Intent就會被解析到NotesList這個activity:
{ action=android.app.action.MAIN }:與此Intent匹配的Activity,將會被看成進入應用的頂級入口。
{ action=android.app.action.MAIN, category=android.app.category.LAUNCHER }:這是目前Launcher實際使用的 Intent,用於生成Launcher的頂級列表。
{ action=android.app.action.VIEW data=content://com.google.provider.NotePad/notes }:
顯示"content://com.google.provider.NotePad/notes"下的全部便箋的列表,使用者能夠遍歷列表,而且察看某便箋的詳細信息。
{ action=android.app.action.PICK data=content://com.google.provider.NotePad/notes }:
顯示"content://com.google.provider.NotePad/notes"下的便箋列表,讓用戶能夠在列表中選擇一個,而後將選擇的便箋的 URL返回給調用者。
{ action=android.app.action.GET_CONTENT type=vnd.android.cursor.item/vnd.google.note }:和上面的action爲pick的Intent相似,不一樣的是這個Intent容許調用者(在這裏指要調用NotesList的某個 Activity)指定它們須要返回的數據類型,系統會根據這個數據類型查找合適的 Activity(在這裏系統會找到NotesList這個Activity),供用戶選擇便箋。
第二個Activity是com.google.android.notepad.NoteEditor,它爲用戶顯示一條便箋,而且容許 用戶修改這個便箋。
它定義了兩個intent-filter,因此具備兩個功能。
第一個功能是,當數據類型爲 vnd.android.cursor.item/vnd.google.note時,容許用戶查看和修改一個便籤(action爲 android.app.action.VIEW和android.app.action.EDIT)。
第二個功能是,當數據類型爲 vnd.android.cursor.dir/vnd.google.note,爲調用者顯示一個新建便箋的界面,並將新建的便箋插入到便箋列表中(action爲android.app.action.INSERT)。
有了這兩個功能,下面的Intent就會被解析到NoteEditor這個activity:
{ action=android.app.action.VIEW data=content://com.google.provider.NotePad/notes/{ID}} :向用戶顯示標識爲 ID的便箋。
{ action=android.app.action.EDIT data=content://com.google.provider.NotePad/notes/{ID}}:容許用戶編輯標識爲ID的便箋。
{ action=android.app.action.INSERT data=content://com.google.provider.NotePad/notes }:在「content://com.google.provider.NotePad/notes」這個便箋列表中建立一個新的空便箋,並容許用戶編輯這個便籤。當用戶保存這個便箋後,這個新便箋的URI將會返回給調用者。
最後一個Activity是com.google.android.notepad.TitleEditor,它容許用戶編輯便箋的標題。
它能夠被實現爲一個應用能夠直接調用(在Intent中明確設置component屬性)的類,不過這裏咱們將爲你提供一個在現有的數據上發佈可選操做的方法。
在這個 Activity的惟一的intent-filter中,擁有一個私有的action: com.google.android.notepad.action.EDIT_TITLE,代表容許用戶編輯便箋的標題。
和前面的view和edit 動做同樣,調用這個Intent 的時候,也必須指定具體的便箋(type爲vnd.android.cursor.item/vnd.google.note)。不一樣的是,這裏顯示和編輯的只是便箋數據中的標題。
除了支持缺省類別(android.intent.category.DEFAULT),標題編輯器還支持另外兩個標準類別: android.intent.category.ALTERNATIVE和
android.intent.category.SELECTED_ALTERNATIVE。
實現了這兩個類別以後,其它 Activity就能夠調用queryIntentActivityOptions(ComponentName, Intent[], Intent, int)查詢這個Activity提供的action,而不須要了解它的具體實現;
或者調用addIntentOptions(int, int, ComponentName, Intent[], Intent, int, Menu.Item[])創建動態菜單。須要說明的是,在這個intent-filter中有一個明確的名稱(經過android:label= "@string/resolve_title"指定),在用戶瀏覽數據的時候,若是這個Activity是數據的一個可選操做,指定明確的名稱能夠爲用戶提供一個更好控制界面。
有了這個功能,下面的Intent就會被解析到TitleEditor這個Activity:
{ action=com.google.android.notepad.action.EDIT_TITLE data=content://com.google.provider.NotePad/notes/{ID}}:顯示而且容許用戶編輯標識爲ID的便箋的標題。app