綁定帳號登入

Android 台灣中文網

打印 上一主題 下一主題

[教程] 詳解Android Intent

[複製連結] 查看: 1845|回覆: 0|好評: 0
跳轉到指定樓層
樓主
暗桌之光 | 收聽TA | 只看該作者 回帖獎勵 |倒序瀏覽 |閱讀模式
發表於 2012-3-19 14:55

馬上加入Android 台灣中文網,立即免費下載應用遊戲。

您需要 登錄 才可以下載或查看,沒有帳號?註冊

x
一、 Intent 作用
        Intent被譯作意圖,其實還是很能傳神的,Intent期望做到的,就是把實現者和調用者完全解耦,調用者專心將以意圖描述清晰,發送出去,就可以夢想成真,達到目的。

        Intent 是一個將要執行的動作的抽像描述,一般來說是作為參數來使用,由Intent來協助完成android各個組件之間的通訊。比如說調用 startActivity()來啟動一個activity,或者由broadcaseIntent()來傳遞給所有感興趣的 BroadcaseReceiver, 再或者由startService()/bindservice()來啟動一個後台的service.所以可以看出來,intent主要是用來啟動其他的 activity 或者service,所以可以將intent理解成activity之間的粘合劑。


二、 Intent的構成

       要在不同的activity之間傳遞數據,就要在intent中包含相應的東西,一般來說數據中最基本的應該包括:

-  Action: 當日常生活中,描述一個意願或願望的時候,總是有一個動詞在其中。比如:我想 三個俯臥撐;我要 一部x片;我要 一部血淚史,之類云云。在Intent中,Action就是描述看、做、寫等動作的,當你指明了一個Action,執行者就會依照這個動作的指示,接受相關輸入,表現對應行為,產生符合的輸出。在Intent類中,定義了一批量的動作,比如ACTION_VIEWACTION_PICK ,之類的,基本涵蓋了常用動作,整一個降龍十八掌全集


標準的Activity Actions
ACTION_MAIN                             作為一個主要的進入口,而並不期望去接受數據
ACTION_VIEW                             向用戶去顯示數據
ACTION_ATTACH_DATA               用於指定一些數據應該附屬於一些其他的地方,例如,圖片數據應該附屬於聯繫人
ACTION_EDIT                              訪問已給的數據,提供明確的可編輯
ACTION_PICK                              從數據中選取一個子項目,並返回你所選中的項目
ACTION_CHOOSER                      顯示一個activity選取器,允許用戶在進程之前選取他們想要的
ACTION_GET_CONTENT               允許用戶選取特殊種類的數據,並返回(特殊種類的數據:照一張相片或錄一段音)
ACTION_DIAL                               撥打一個指定的號碼,顯示一個帶有號碼的用戶界面,允許用戶去啟動呼叫
ACTION_CALL                              根據指定的數據執行一次呼叫
(ACTION_CALL在應用中啟動一次呼叫有缺陷,多數應用ACTION_DIAL,ACTION_CALL不能用在緊急呼叫上,緊急呼叫可以用ACTION_DIAL來實現)
ACTION_SEND                             傳遞數據,被傳送的數據沒有指定,接收的action請求用戶發數據
ACTION_SENDTO                         發送一個訊息到指定的某人
ACTION_ANSWER                        處理一個打進電話呼叫
ACTION_INSERT                          插入一條空項目到已給的容器
ACTION_DELETE                          從容器中刪除已給的數據
ACTION_RUN                               執行數據,無論怎麼
ACTION_SYNC                             同步執行一個數據
ACTION_PICK_ACTIVITY              為已知的Intent選取一個Activity,返回別選中的類
ACTION_SEARCH                         執行一次搜索
ACTION_WEB_SEARCH                執行一次web搜索
ACTION_FACTORY_TEST              工場測試的主要進入點,


標準的廣播Actions
ACTION_TIME_TICK                   當前時間改變,每分鐘都發送,不能通過組件聲明來接收,只有通過Context.registerReceiver()方法來註冊
ACTION_TIME_CHANGED            時間被設定
ACTION_TIMEZONE_CHANGED   時間區改變
ACTION_BOOT_COMPLETED       系統完成啟動後,一次廣播
ACTION_PACKAGE_ADDED         一個新應用包已經安裝在設備上,數據包括包名(最新安裝的包程式不能接收到這個廣播)
ACTION_PACKAGE_CHANGED    一個已存在的應用程式包已經改變,包括包名
ACTION_PACKAGE_REMOVED   一個已存在的應用程式包已經從設備上移除,包括包名(正在被安裝的包程式不能接收到這個廣播)
ACTION_PACKAGE_RESTARTED 用戶重新開始一個包,包的所有進程將被殺死,所有與其聯繫的執行時間狀態應該被移除,包括包名(重新開始包程式不能接收到這個廣播)
ACTION_PACKAGE_DATA_CLEARED 用戶已經清楚一個包的數據,包括包名(清除包程式不能接收到這個廣播)
ACTION_BATTERY_CHANGED 電池的充電狀態、電荷級別改變,不能通過組建聲明接收這個廣播,只有通過Context.registerReceiver()註冊
ACTION_UID_REMOVED 一個用戶ID已經從系統中移除


-  Data(數據): 要事實的具體的數據,一般由一個Uri變量來表示

下面是一些簡單的例子:

ACTION_VIEW content://contacts/1 //顯示identifier為1的聯繫人的訊息。
ACTION_DIAL  content://contacts/1 //給這個聯繫人打電話

除了Action和data這兩個最基本的元素外,intent還包括一些其他的元素,

-  Category(範疇):  指定Action範圍,這 個選項指定了將要執行的這個action的其他一些額外的約束.有時通過Action,配合Data或Type,很多時候可以準確的表達出一個完整的意圖 了,但也會需要加一些約束在裡面才能夠更精準。比如,如果你雖然很喜歡做俯臥撐,但一次做三個還只是在特殊的時候才會發生,那麼你可能表達說:每次吃撐了 的時候 ,我都想做三個俯臥撐。吃撐了,這就對應著Intent的Category的範疇,它給所發生的意圖附加一個約束。在Android中,一個實例 是:所有應用的主Activity(單獨啟動時候,第一個執行的那個Activity...),都需要一個Category為 CATEGORY_LAUNCHER,Action為ACTION_MAIN的Intent。


-  Type(數據類型):   用於指定類型,以供過濾(比如ACTION_VIEW同時指定為Type為Image,則調出瀏覽圖片的應用).一般Intent的數據類型能夠根據數據本身進行判定,但是通過設定這個屬性,可以強制採用顯式指定的類型而不再進行判定。

-  Component(組件):   當 我們常用Action,Data/Type,Category去描述一個意圖,這是Android推薦,這種模式稱:Implicit Intents. 通過這種模式,提供一種靈活可擴展的模式,給用戶和第三方應用一個選取權。比如:一個郵箱軟體,大部分功能都好,就是選取圖片的功能做的很土,怎麼辦?如 果它採用的是Implicit Intents,那麼它就是一個開放的體繫了,手機中沒有其他圖片選取功能的情況下,可以繼續使用郵箱默認的,如果有,你可以任意選取來替代原有模塊完成 這功能,一切都自然而然。但這種模式需要付出性能上的開銷,因為畢竟有一個檢索過程。於是,Android提供了另一種模式,叫做Explicit Intents ,就需要Component的幫助了。Component就是完整的類名,形如com.xxxxx.xxxx ,一旦指明了,可以直接調用,自然是速度快. 適合在你明確知道這就是一個內部模塊的時候,使用它。

-  Extras(附加訊息):    是其它所有附加訊息的集合。使用extras可以為組件提供擴展訊息,比如,如果要執行「發送電子郵件」這個動作,可以將電子郵件的標題、正文等保存在extras裡,傳給電子郵件發送組件。

-  Flags(標誌位):   能 識別,有輸入,整個Intent基本就完整了,但還有一些附件的指令,需要放在Flags中帶過去。顧名思義,Flags是一個整形數,有一些列的標誌 位構成,這些標誌,是用來指明執行模式的。比如,你期望這個意圖的執行者,和你執行在兩個完全不同的任務中(或說進程也無妨吧...),就需要設定FLAG_ACTIVITY_NEW_TASK 的標誌位。

Android 的一個特色就是 application A 的 activity 可以啟動 application B 的 activity,儘管 A 和 B 是毫無干係的,而在用戶看來,兩個場景緊密聯繫,視覺上二者構成了一個整體。Android 就是把這種誤覺定義為 Task,它既不是 class,也不是 AndroidMainifest.xml 中的一個元素。從表現上看 Task 就像是一個 stack,一個一個的 activity 是構成 stack 的元素,做著入棧 (push) 和出棧 (pop-up)這樣簡單重複性的勞動。

默 認的規則總是滿足大多數的應用場景,但是也總會有一些例外打破習以為常的慣例。Task 的默認規則同樣並非牢不可破,修改的方法還是有的。借助 Intent 中的 flag 和 AndroidMainifest.xml 中 activity 元素的屬性,就可以控制到 Task 裡 Activity 的關聯關係和行為。

在 android.content.Intent 中一共定義了20種不同的 flag,其中和 Task 緊密關聯的有四種:

FLAG_ACTIVITY_NEW_TASK
FLAG_ACTIVITY_CLEAR_TOP
FLAG_ACTIVITY_RESET_TASK_IF_NEEDED
FLAG_ACTIVITY_SINGLE_TOP
在使用這四個 flag 時,一個 Intent 可以設定一個 flag,也可以選取若干個進行組合。

默 認情況下,通過 startActivity() 啟動一個新的 Activity,新的 Activity 將會和調用者在同一個 stack 中。但是,如果在傳遞給 startActivity() 的 Intent 對像裡包含了 FLAG_ACTION_NEW_TASK,情況將發生變化,系統將為新的 Activity 「尋找」一個不同於調用者的 Task。不過要找的Task 是不是一定就是 NEW 呢?如果是第一次執行,則這個設想成立,如果說不是,也就是說已經有一個包含此 Activity 的Task 存在,則不會再啟動 Activity。

如果 flag 是 FLAG_ACTIVITY_CLEAR_TOP,同時當前的 Task 裡已經有了這個 Activity,那麼情形又將不一樣。Android 不但不會啟動新的 Activity 實例,而且還會將 Task 裡 該 Activity 之上的所有 Activity 一律結束掉,然後將 Intent 發給這個已存在的 Activity。Activity 收到 Intent 之後,可以在 onNewIntent() 裡做下一步的處理,也可以自行結束然後重新創建自己。如果 Activity 在 AndroidMainifest.xml 裡將啟動模式設定成multiple,– 默認模式,並且 Intent 裡也沒有設定 FLAG_ACTIVITY_SINGLE_TOP,那麼它將選取後者。否則,它將選取前者。FLAG_ACTIVITY_CLEAR_TOP 還可以和 FLAG_ACTION_NEW_TASK 配合使用。

如果 flag 設定的是 FLAG_ACTIVITY_SINGLE_TOP,則意味著如果 Activity 已經是執行在 Task 的 top,則該 Activity 將不會再被啟動。

三、 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中的所有<intent-filter>及其中定義的Intent,通過 PackageManager(註:PackageManager能夠得到當前設備上所安裝的application package的訊息) 來查找能過處理這個Intent的component。在這個解析過程中,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如何定義及如何被解析。這個應用可以讓用戶瀏覽便箋列表、查看每一個便箋的詳細訊息。

Manifest.xml
  1. <manifest xmlns:android="http://schemas.android.com/apk/res/android"   
  2. package="com.google.android.notepad">   
  3.     <application android:icon="@drawable/app_notes"   
  4. android:label="@string/app_name">   
  5.     <provider class="NotePadProvider"   
  6. android:authorities="com.google.provider.NotePad" />   
  7.     <activity class=".NotesList"="@string/title_notes_list">   
  8.       <intent-filter>   
  9.         <action android:value="android.intent.action.MAIN"/>   
  10.         <category android:value="android.intent.category.LAUNCHER" />   
  11.       </intent-filter>   
  12.       <intent-filter>   
  13.         <action android:value="android.intent.action.VIEW"/>   
  14.         <action android:value="android.intent.action.EDIT"/>   
  15.         <action android:value="android.intent.action.PICK"/>   
  16.         <category android:value="android.intent.category.DEFAULT" />   
  17.         <type android:value="vnd.android.cursor.dir/vnd.google.note" />   
  18.       </intent-filter>   
  19.       <intent-filter>   
  20.         <action android:value="android.intent.action.GET_CONTENT" />   
  21.         <category android:value="android.intent.category.DEFAULT" />   
  22.         <type android:value="vnd.android.cursor.item/vnd.google.note" />   
  23.       </intent-filter>   
  24.     </activity>   
  25.     <activity class=".NoteEditor"="@string/title_note">   
  26.       <intent-filter android:label="@string/resolve_edit">   
  27.         <action android:value="android.intent.action.VIEW"/>   
  28.         <action android:value="android.intent.action.EDIT"/>   
  29.         <category android:value="android.intent.category.DEFAULT" />   
  30.         <type android:value="vnd.android.cursor.item/vnd.google.note" />   
  31.       </intent-filter>   
  32.       <intent-filter>   
  33.         <action android:value="android.intent.action.INSERT"/>   
  34.         <category android:value="android.intent.category.DEFAULT" />   
  35.         <type android:value="vnd.android.cursor.dir/vnd.google.note" />   
  36.       </intent-filter>   
  37.     </activity>   
  38.     <activity class=".TitleEditor"="@string/title_edit_title"   
  39. android:theme="@android:style/Theme.Dialog">   
  40.       <intent-filter android:label="@string/resolve_title">   
  41.         <action android:value="com.google.android.notepad.action.EDIT_TITLE"/>   
  42.         <category android:value="android.intent.category.DEFAULT" />   
  43.         <category android:value="android.intent.category.ALTERNATIVE" />   
  44.         <category android:value="android.intent.category.SELECTED_ALTERNATIVE"/>   
  45.         <type android:value="vnd.android.cursor.item/vnd.google.note" />   
  46.       </intent-filter>   
  47.     </activity>   
  48. </application>   
  49. </manifest>
複製代碼


例子中的第一個Activity 是com.google.android.notepad.NotesList,它是應用的主入口,提供了三個功能,分別由三個 intent-filter進行描述:
        1、第一個是進入便箋應用的頂級入口(action為android.app.action.MAIN)。類型為android.app.category.LAUNCHER表明這個Activity將在Launcher中列出。
        2、第二個是,當type為vnd.android.cursor.dir/vnd.google.note(保存便箋記錄的目錄) 時,可以查看可用的便箋(action為android.app.action.VIEW),或者讓用戶選取一個便箋並返回給調用者(action為 android.app.action.PICK)。
        3、第三個是,當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的便箋的標題。
「用Android 就來APK.TW」,快來加入粉絲吧!
Android 台灣中文網(APK.TW)

評分

參與人數 2幫助 +2 收起 理由
黃華協 + 1 讚一個!
harrisfeng + 1 很給力!

查看全部評分

收藏收藏1 分享分享 分享專題
用Android 就來Android 台灣中文網(https://apk.tw)
回覆

使用道具 舉報

您需要登錄後才可以回帖 登錄 | 註冊

本版積分規則