Android - Intents and Intent Filters
- 1. Intent Types
- 2. Building an Intent
- 2.1. Example explicit intent
- 2.2. Example implicit intent
- 2.3. Forcing an app chooser
原文:http://developer.android.com/guide/components/intents-filters.html
Intent 是傳遞訊息的物件,可以用來跟其他 APP Component 要求一個動作,Intents 讓幾個 Components 之間交流更加方便,以下有三個使用情況:
- 啟動
Activity
:
一個 Activity 相當於 APP 中的一個畫面。你可以透過傳遞 Intent 到startActivity()
來啟動一個新的 Activity 實例。Intent 描述要啟動哪種 Activity 還有攜帶必須的資料。 - 啟動
Service
:
Service 是在背景運作的 Component 而且沒有使用者介面,你可以透過將 Intent 傳遞到startService()
來啟動 Service 去處理一次性操作(像是下載一個檔案)。Intent 描述要啟動的 Service 來啟動並攜帶必要的資料給他。
如果 Service 是以 client-server 介面設計的,你可以透過傳入 Intent 到bindService()
綁定服務到其他 Component。更多資訊詳見 Services 手冊。 - 傳送
Broadcast
:
Broadcast 是任何 APP 都可以接收的訊息。系統傳送許多系統事件的廣播,像是當系統開機或裝置開始充電等。你可以透過傳入 Intent 到sendBroadcast()
、sendOrderedBroadcast()
或sendStickyBroadcast()
傳送廣播到其他 APP。
Intent Types
Intent 有兩種類型:
Explicit intents(明確意圖)有具體說明要啟動的 Component 名稱(完整的 Class name),你會在你自己的 APP 使用 Explicit intent 來啟動 Component 因為你知道 Activity 或 Service 的 Class name。例如啟動一個新的 Activity 來回映使用者的動作或是啟動一個 Service 在背景下載檔案。
Implicit intents(含蓄意圖)沒有指定的 Component 名稱,Intent 宣告要做的動作,並允許其他 APP 的 Component 去應對他。舉例來說,如果你要顯示出使用者在地圖中的位置,你可以使用 Implicit intent 來要求其他有這方面能力的 APP 來顯示出地圖中特定的位置。
當你建立一個 Explicit intent 來啟動 Activity 或 Service,系統會立刻啟動 Intent 物件指定的 APP Component。
當你建立 Implicit intent,Android 系統會透過比較 Intent 與 Intent filters 在 Manifest 長案中宣告的內容來尋找並啟動適合的 Component。如果 Intent 符合 Intent filter,系統會啟動 Component 並傳遞 Intent 物件,如果有多個 Intent filter 相符,系統會顯示一個對話,讓使用者選擇要用那個 APP。
Intent filter 在 APP 的 Manifest 中宣告,用來說明 Intent 想接收 Component 的類型。例如,為一個 Activity 宣告 Intent filter,讓其他 APP 可以為了特定類型的 Intent 直接啟動你的 Activity。同樣的,你可以不幫你的 Activity 宣告任何 Intent filter,他就只能被 Explicit Intent 啟動。
小心:為了保證你的 APP 是安全的,總是使用 Explicit intent 來啟動 Service 並且不要為你的 Services 宣告 intent filter,使用 Implicit internt 啟動 Service 危害安全的,因為你不能確定那個服務會回應這個 Intent,使用者看不到那個 Service 被啟動了,從 Android 5.0(API level 21)開始,系統會在你使用 Implicit intent 呼叫
bindService()
時丟出例外。
上圖為 Implicit intent 如何重送給系統來啟動其他 Activity:[1] 一個 Activity
(Activity A) 用 Action 的內容建立一個 Intent
然後傳入 startActivity()
方法。 [2] Android 系統搜尋所有 APP,尋找一個符合 Intent
的 Intent filter
。當找到時 [3] 系統會啟動符合的 Activity
(Activity A)呼叫他的 onCreate()
方法並將 Intent
傳給他。
Building an Intent
Intent 物件攜帶資訊讓 Android 系統確定那個 Component 要被啟動(像是確切的 Component 名稱或是 Component 種類),為了正確的執行這個動作也會有額外的資訊讓接收的 Component 使用(像是要採取的行動,和這個動作需要的資料)。
Intent 主要的資訊內容如下:
Component name
要啟動的 Component 名稱。
這是可選項目,但這是要讓 Intent explicit 的話就是很重要的資訊,代表 Intent 應該只能被傳遞給被定義名稱的 APP Component,如果沒有 Component name,Intent 就會是 Implicit 的,系統藉由其他的 Intent 資訊(像是下面會介紹的 Action、Data 和 Category)來決定應該要將 Intent 傳遞給那個 Component。如果你需要啟動你 APP 中特定的 Component,你應該具體說明 Component name。
Note:當啟動 Service 時,永遠都要明確指定 Component name,否則你無法確定那個 Service 會回應你的 Intent,使用者也看不到那個 Service 啟動了。
這裡是要傳入 ComponentName
物件,也就是目標 Component 的完整 Class name,包含 APP 的 Package name。例如,com.example.ExampleActivity
。你可以呼叫 setComponent()
、setClass()
、setClassName
或是用 Intent 的建構式來設定 Component name。
Action
是一個字串,用來表示要做的動作(像是 view 或 pick)。
在 Broadcast intent 的例子中,發生了正在報告的 Action,Action 主要決定了 Intent 其他部分的結構,特別是他包含了哪些 Data 或 Extras。
你可以在你的 APP(或是給其他 APP 用來請求你 APP 中的 Components) 指定自己的 Actions 來給 Intent 使用,但是你通常應該使用 Intent 類別或其他 framework 的類別中 constants defined 的 Action。這裡有一些用來啟動 Activity 的常見 Actions:
- ACTION_VIEW
當你有一些資訊要讓 Activity 顯示給使用者看時,在 Intent 中用這個 Action。像是畫廊 APP 裡要看的照片,或是用來在地圖 APP 上查看的地址。 - ACTION_SEND
也被稱為 “share” Intent,當你有一些資料要讓使用者分享到其他 APP 去,像是郵件 APP 或是社交分享 APP,你應該要在使用這個 Action 呼叫startActivity()
。
更多一般定義的 Action 內容,參考 Intent 類別的文件,其他 Actions 被定義在 Android framework 中,像是 Settings 的 Action 用來在系統設定 APP 中打開特定的畫面。
你可以使用 setAction()
或是 Intent 的建構式來為 Intent 設定具體的 Action。
如果你要定義自己的 Action,請使用你 APP 的 Package name 作為前綴,像是:static final String ACTION_TIMMETRAVEL = "com.example.action.TIMETRAVEL";
Data
Data 是參考到要用到的資料的 URI(URI 物件)和/或 MIME 類型的資料。資料的類型是由 Intent 的 Action 決定。例如,如果 Action 是 ACTION_EDIT
,資料應該要包含被編輯的文件的URI。
當 Intent 建立時,通常需要具體說明資料的類型(MIME Type)還有資料的 URI。例如,儘管 URI 的格式是相似的,Activity 允許顯示影像但可能不允許播放影片檔。所以具體說明資料的 MIME type 可以幫助 Android 系統尋找最佳的 Component 來回應你的 Intent。然而 MIME type 有時可以透過 URI 推理出來,特別是當資料是 content
時(URI 指示資料在裝置上的位置並由 ContentProvider
控制,這樣就能讓資料的 MIME type 變成系統可以看見的)。
要只設定資料 URI 可以呼叫 setData()
,只設定 MIME type 可以呼叫 setType()
,必要時可以用 setDataAndType
一次把 URI 和 MIME type。
Category
Category 是包含有關要處理這個 Intent 的 Component 類型的額外資訊字串。Intent 中可以放入任意數量的 Category 描述,但大多數的 Intent 不需要 Category,這裡有一些常見的 Categories:CATEGORY_BROWSABLE
目標 Activity 允許自己啟動網頁瀏覽器來顯示透過連結參考到的資料,像是影像或 e-mail 訊息。CATEGORY_LAUNCHER
這種 Activity 是任務中初始的 Activity,並且列於系統的應用程式啟動程序。
可以在 Intent 的文件來察看完整的 Category 清單。
可以用 addCategory
來加入 Category。
以上列出的屬性(Component name、Action、Data、Category)用來為 Intent 定義出他的特性。Android 系統透過讀取這些屬性,可以決定哪個 APP Component 應該被啟動。
然而 Intent 可以攜帶一些額外的資料,而不影響系統決定使用哪個 Component,Intent 也支援下面這些資訊:
Extras
Extra 是一組 Key-value pair,用來攜帶完成請求所需要的額外的資訊,就像一些 Action 使用特定種類的資料 URI,有些 Action 也需要使用特定的 Extra。
可以使用各種 putExtra()
方法來加入 Extra 資料,每個方法都有兩個參數:Key 名稱和 Value。你也可以建立一個 Bundle
物件將所有 Extra 用 putExtra()
插入 Intent 的 Bundle 中。
例如當你用 ACTION_SEND
來建立一個 Intent 用來傳送 email,你可以用 EXTRA_EMAIL
Key 來宣告 to
收信人,並且用 EXTRA_SUBJECT
來宣告 subject
主旨。
Intent 類別宣告很多 EXTRA_*
常數來標準化資料型別,如果你需要宣告自己的 Extra keys(為了讓你的的 APP 收到 Intent),請確認他包含你的 APP 的 package name 像下面這樣:static final String EXTRA_GIGAWATTS = "com.example.EXTRA_GIGAWATTS";
Flags
Flags 定義在 Intent 類別中,作為 Intent 的 Metadata 的功能。Flags 可以告訴 Android 系統如何啟動一個 Activity(例如,Activity 應該是屬於哪一個 task
),還有在啟動後如何對應他(例如,他是否屬於最近活動的 Activities 列表)。
更多資訊詳見 setFlags() 方法
Example explicit intent
Explicit intent 用來啟動特定的 APP Component,像是你的 APP 中特定的 Activity 或是 Service,要建立一個 Explicit intent 要為 Intent 物件定義 Component 名稱,其他 Intent 屬性則是可選的。
例如,要為你的 APP 建立一個 Service,用來從網路上下載檔案,叫做 DownloadService
,你可以像這樣來寫程式碼:// Executed in an Activity, so 'this' is the Context
// The fileUrl is a string URL, such as "http://www.example.com/image.png"
Intent downloadIntent = new Intent(this, DownloadService.class);
downloadIntent.setData(Uri.parse(fileUrl));
startService(downloadIntent);
Intent(Context, Class)
建構式傳入 APP Context 還有 Component 的 Class 物件。因此在這個 APP 中這個 Intent 明確的啟動 DownloadService
類別。
更多關於建立與啟動 Service 的資訊,詳見 Service 手冊。