Android中Intent詳解

可以毫不誇張地說:Intent是整個Android應用的脈絡與靈魂

在一個Android 應用中,主要是由四種組件組成(Activities, Services, Broadcast receivers, Content providers),而這四種組件是獨立的,它們之間可以互相調用,協調工作,最終組成一個真正的Android應用。在這些組件之間的通訊,主要是由Intent協助完成的。如果我們把Activity比作積木的話,那麼Intent就是膠水,把不同的積木粘起來,構成我們搭建的房子(應用)。
Intent負責對應用中一次操作的動作及動作涉及數據 進行描述,Android則根據此Intent的描述,負責找到對應的組件,將Intent傳遞給調用的組件,並完成組件的調用。因此,Intent在這裏起着一個媒體中介的作用,專門提供組件互相調用的相關信息, 實現調用者與被調用者之間的解耦控制。就像我們打電話到出租車公司叫計程車,而不是直接到街道上叫車,我們給出租車公司打電話,表明我們的意圖(Intent),當服務員接到此意圖,就依據我們的意圖去挑選最合適的計程車,然後派遣它來接我們。
例如,在一個聯繫人 維護的應用中,當我們在一個聯繫人列表屏幕(假設對應的Activity爲listActivity)上,點擊某個聯繫人後,希望能夠跳到此聯繫人的詳細信息屏幕(假設對應的Activity爲detailActivity)。爲了實現這個目的,listActivity 需要構造一個Intent,這個Intent用於告訴系統,我們要做“查看”動作,此動作對應的查看對象是“某聯繫人”,然後調用startActivity (Intent intent),將構造的Intent傳入,系統會根據此Intent中的描述,到AndroidManifest.xml中找到滿足此Intent要求的Activity,系統會調用找到的Activity-detailActivity,最終傳入Intent,detailActivity則會根據此Intent中的描述,執行相應的的操作。
一、 抽象描述要描述什麼

在Android參考文檔 中,對Intent的定義是執行某操作的一個抽象描述。我們先來看看這裏的抽象描述,到底描述了什麼。
首先 ,是對要執行的動作(action)的一個簡要描述,如
ACTION_ VIEW(查看)、 ACTION_ EDIT(修改)等,Android爲我們定義了一套標準動作:

代碼:

ACTION_MAIN

ACTION_VIEW

ACTION_ATTACH_DATA

ACTION_EDIT

ACTION_PICK

ACTION_CHOOSER

ACTION_GET_CONTENT

ACTION_DIAL

ACTION_CALL

ACTION_SEND

ACTION_SENDTO

ACTION_ANSWER

ACTION_INSERT

ACTION_DELETE

ACTION_RUN

ACTION_SYNC

ACTION_PICK_ACTIVITY

ACTION_SEARCH

ACTION_WEB_SEARCH

此外,我們還可以根據應用的需要,定義我們自己的動作,並可定義相應的Activity來處理我們的自定義動作。

其次,是執行動作要操作的數據(data),Android中採用指向數據的一個URI來表示,如在聯繫人應用中,一個指向某聯繫人的URI可能爲:content://contacts/1。這種Uri表示,通過Uri這個類來描述,具體可以參考android.net.Uri類的文檔。

以聯繫人應用爲例,以下是一些action/data對,及其它們要表達的意圖:

代碼:

ACTION_VIEW content://contacts/people/1 -- 顯示標識符爲“1”的聯繫人的信息。

ACTION_DIAL content://contacts/people/1 -- 將標識符爲“1”的聯繫人的號碼顯示在電話的撥號面板上。

ACTION_VIEW tel:123 -- 將號碼123顯示在電話的撥號面板上。 (與ACTION_DIAL有何區別?只說:Note how the VIEW action does what what is considered the most reasonable thing for a particular URI.)

ACTION_DIAL tel:123 -- 將號碼123顯示在電 話的撥號面板上。

ACTION_EDIT content://contacts/people/1 --編輯標識符爲“1”的聯繫人的信息。

ACTION_VIEW content://contacts/people/ -- 顯示所有聯繫人的列表。

category (類別),是被執行動作的附加信息。例如 LAUNCHER_CATEGORY 表示 Inten t的接受者應該在 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來處理已經存在的這樣的“短語”,從而改變這些“短語”的行爲。

二、 Android如何解析Intent

在應用中,我們可以以兩種形式來使用Intent:

  • 直接Intent :指定了component屬性的Intent(調用setComponent(ComponentName)或者setClass(Context, Class)來指定)。通過指定具體的組件類,通知應用啓動對應的組件。
  • 間接Intent :沒有指定comonent屬性的Intent。這些Intent需要包含足夠的信息,這樣系統才能根據這些信息,在所有的可用組件中,確定滿足此Intent的組件。

      對於直接Intent,Android不需要去做解析,因爲目標組件已經很明確,Android需要解析的是那些間接Intent,通過解析,將Intent映射給可以處理此Intent的Activity、Broadcaset receiver或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,解析得到的目標組件必須至少包含這兩個類別。

三、應用例子
        以下,以Android SDK中的便箋例子來說明,Intent如何定義及如何被解析。這個應用可以讓用戶瀏覽便箋列表、查看每一個便箋的詳細信息。

代碼:

        例子中的第一個Activity是com.google.android.notepad.NotesList,它是應用的主入口,提供了三個功能 ,分別由三個intent-filter進行描述:
        1、第一個是進入便箋應用的頂級入口(action爲android.intent.action.MAIN)。類型爲android.intent.category.LAUNCHER表明這個Activity將在Launcher中列出。
        2、第二個是,當type爲vnd.android.cursor.dir/vnd.google.note(保存便箋記錄的目錄)時,可以查看編輯可用的便箋(action爲android.intent.action.VIEW| android.intent.action.EDIT ),或者讓用戶選擇一個便箋並返回給調用者(action爲 android.intent.action.PICK)。
        3、第三個是,當type爲vnd.android.cursor.item/vnd.google.note時,返回給調用者一個用戶選擇的便箋 (action爲android.intent.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.intent.action.VIEW和android.intent.action.EDIT)。

第二個功能是,當數據類型爲 vnd.android.cursor.dir/vnd.google.note,爲調用者顯示一個新建便箋的界面,並將新建的便箋插入到便箋列表中 (action爲android.intent.action.INSERT)。
有了這兩個功能,下面的Intent就會被解析到NoteEditor這個activity:

代碼:

{ action=android.intent.action.VIEW data=content://com.google.provider.NotePad/notes/{ID}} :向用戶顯示標識爲ID的便箋。


{ action=android.intent.action.EDIT data=content://com.google.provider.NotePad/notes/{ID}}:允許用戶編輯標識爲ID的便箋。

{ action=android.intent.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的便 箋的標題。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章