天天看點

安卓開發指南之Intent 和 Intent 過濾器

本系列的文章全部為學習摘要,不偏重各種細節展示,更多的是安卓體系重要節點的羅列,并适時加入少量自己的了解分析,以便能快速的回顧安卓體系結構和那些重要的技術點。

Intent 是一個消息傳遞對象,您可以使用它從其他應用元件請求操作。盡管 Intent 可以通過多種方式促進元件之間的通信,但其基本用例主要包括以下三個:

  • 啟動 Activity:通過将 Intent 傳遞給 startActivity(),您可以啟動新的 Activity 執行個體。Intent 描述了要啟動的 Activity,并攜帶了任何必要的資料。如果您希望在 Activity 完成後收到結果,請調用 startActivityForResult()。在 Activity 的 onActivityResult() 回調中接收結果。
  • 啟動服務:通過将 Intent 傳遞給 startService(),您可以啟動服務執行一次性操作(例如,下載下傳檔案)。如果服務旨在使用用戶端-伺服器接口,則通過将 Intent 傳遞給 bindService(),您可以從其他元件綁定到此服務。
  • 傳遞廣播:通過将 Intent 傳遞給 sendBroadcast()、sendOrderedBroadcast() 或 sendStickyBroadcast(),您可以将廣播傳遞給其他應用。

Intent 分為兩種類型:

  • 顯式 Intent:按名稱(完全限定類名)指定要啟動的元件。
  • 隐式 Intent :不會指定特定的元件,而是聲明要執行的正常操作,進而允許其他應用中的元件來處理它。Android 系統通過将 Intent 的内容與在裝置上其他應用的清單檔案中聲明的 Intent 過濾器進行比較,進而找到要啟動的相應元件。

Intent 過濾器是應用清單檔案中的一個表達式,它指定該元件要接收的 Intent 類型。 為了確定應用的安全性,啟動 Service 時,請始終使用顯式 Intent,且不要為服務聲明 Intent 過濾器。

建構 Intent–Intent 中包含的主要資訊如下:

  • 元件名稱 ComponentName:

    可選項,但也是建構顯式 Intent 的一項重要資訊。如需在應用中啟動特定的元件,則應指定該元件的名稱。可以使用 setComponent()、setClass()、setClassName() 或 Intent 構造函數設定元件名稱。

  • 操作Action

    指定要執行的通用操作(例如,“檢視”或“選取”)的字元串。系統自帶了一些操作,比如ACTION_VIEW和ACTION_SEND;若要定義自己的操作,請確定将應用的軟體包名稱作為字首。 例如:

    static final String ACTION_TIMETRAVEL = “com.example.action.TIMETRAVEL”;

  • 資料Data和類型MIME

    引用待操作資料和/或該資料 MIME 類型的 URI(Uri 對象)。提供的資料類型通常由 Intent 的操作決定。要僅設定資料 URI,請調用 setData()。 要僅設定 MIME 類型,請調用 setType()。如有必要,您可以使用 setDataAndType() 同時顯式設定二者。注意 setData() 和 setType(),會互相抵消彼此的值。

  • 類别Category

    一個包含應處理 Intent 元件類型的附加資訊的字元串。 您可以将任意數量的類别描述放入一個 Intent 中,但大多數 Intent 均不需要類别。您可以使用 addCategory() 指定類别。當不指定時,預設有CATEGORY_DEFAULT類别。

  • 附加資料Extra

    攜帶完成請求操作所需的附加資訊的鍵值對。傳遞的資料包括基本資料類型,String,實作序列化的資料和Bundle支援的資料。

  • 标志Flag

    在 Intent 類中定義的、充當 Intent 中繼資料的标志。 标志可以訓示 Android 系統如何啟動 Activity(例如,Activity 應屬于哪個任務),以及啟動之後如何處理(例如,它是否屬于最近的 Activity 清單)。比如FLAG_ACTIVITY_CLEAR_TOP,代表啟動新Activity時,會使任務棧中目标Activity之上的活動出棧。若棧裡無目标,則建立目标,無其它效果。

處理Intent:

使用者可能沒有任何應用處理您發送到 startActivity() 的隐式 Intent。如果出現這種情況,則調用将會失敗,且應用會崩潰。要驗證 Activity 是否會接收 Intent,請對 Intent 對象調用 resolveActivity()。如果結果為非空,則至少有一個應用能夠處理該 Intent,且可以安全調用 startActivity()。 如果結果為空,則不應使用該 Intent。

  • 要公布應用可以接收哪些隐式 Intent,請在清單檔案中使用 元素為每個應用元件聲明一個或多個 Intent 過濾器。每個 Intent 過濾器均根據 Intent 的操作、資料和類别指定自身接受的 Intent 類型。 僅當隐式 Intent 可以通過 Intent 過濾器之一傳遞時,系統才會将該 Intent 傳遞給應用元件。
  • 顯式 Intent 始終會傳遞給其目标,無論元件聲明的 Intent 過濾器如何均是如此。

Intent 解析

當系統收到隐式 Intent 以啟動 Activity 時,它根據以下三個方面将該 Intent 與 Intent 過濾器進行比較,搜尋該 Intent 的最佳 Activity.

  • Intent 操作

    要指定接受的 Intent 操作,Intent 過濾器既可以不聲明任何 元素,也可以聲明多個此類元素。要通過此過濾器,您在 Intent 中指定的操作必須與過濾器中列出的某一操作比對。

  • Intent 資料(URI 和資料類型)

    要指定接受的 Intent 資料, Intent 過濾器既可以不聲明任何 元素,也可以聲明多個此類元素。每個 元素均可指定 URI 結構和資料類型(MIME 媒體類型)。 URI 的每個部分均包含單獨的 scheme、host、port 和 path 屬性:< scheme >://< host >:< port >/< path >。例如:content://com.example.project:200/folder/subfolder/etc

    在此 URI 中,架構是 content,主機是 com.example.project,端口是 200,路徑是 folder/subfolder/etc。

  • Intent 類别

    要指定接受的 Intent 類别, Intent 過濾器既可以不聲明任何 元素,也可以聲明多個此類元素。若要使 Intent 通過類别測試,則 Intent 中的每個類别均必須與過濾器中的類别比對。反之則未必然,Intent 過濾器聲明的類别可以超出 Intent 中指定的數量,且 Intent 仍會通過測試。

另外,PackageManager 提供了一整套 query…() 方法來傳回所有能夠接受特定 Intent 的元件。此外,它還提供了一系列類似的 resolve…() 方法來确定響應 Intent 的最佳元件。 例如,queryIntentActivities() 将傳回能夠執行那些作為參數傳遞的 Intent 的所有 Activity 清單,而 queryIntentServices() 則可傳回類似的服務清單。這兩種方法均不會激活元件,而隻是列出能夠響應的元件。 對于廣播接收器,有一種類似的方法: queryBroadcastReceivers()。

作者: 劉鹹尚