2013年10月15日 星期二

訊息傳遞與過濾器 intents and Intent filters

Android 的四個主要元件為 Activity, Service, Broadcast Receiver, 以及 Content Provider, 
其中, 前三個必須透過 intent 來喚醒.

Intent 是 Android 裡傳遞訊息的元件, 它依不同的方式來呼叫 Activity, Service, BroadCast Receiver. 

* 在 Activity 裡, intent 可能會用於 Context.startActivity(), Activity.startActivityForResult() 來開始一個 Activity; 也可能會用於 Activity.setResult() 來回傳訊息.

* 在 Service 裡, intent 可能會用於 Context.startService() 來開始一個 Service, 或傳遞訊息給已經在運行中的 Service; 也可能用於 Context.bindService() 來建立呼叫元件與 Service 之間的關係.

* 在 Broadcast 裡, intent 用於各種 broadcast 的方法, 例如: Context.sendBroadcast(), Context.sendOrderBroadCast(), Context.sendStickyBroadcast() 都用來傳遞給有興趣的 Broadcast Receiver 接收

由於使用方法不同, intent 用於這三個元件間的訊息傳遞時, 並不會搞混.

再來我們詳細說明一下 intent 物件.

Intent 物件

Intent 是帶有訊息的包裹(集合), 這些訊息傳遞給有興趣的元件. (也就是 Activity, Service 或 Broadcast Receiver)

Intent 物件包含:

Component name

要接收 intent 的元件的名稱.  
可以設定為 package + 元件名稱 (例如: "com.example.project.app.FreneticActivity"), 
如果元件位於 Application manifest 下的 package(例如: "com.example.project"), 也可以直接設為元件名稱(例如: ".FreneticActivity" ), 

如果有設 Component name, intent 會直接傳遞給名稱相符的元件. 如果沒設 Component name 則會透過其他方式來尋找適合接收此 intent 的元件.

Action

Action 是一個字串, 用來描述即將執行的動作. Intent 本身有定義一些 Aciton 如下:


另外,  我們也可以自定義 Action, 但要記得附上 package 路徑
( 例如: "com.example.project.SHOW_COLOR")

我們所要執行的動作(action), 會決定如何給定 data 跟 extras (有點像 method 跟 argument 的關係),  所以 Action 最好是一個 specific 的命名.

Data

Data 是由 (Data 的) URI + (Data 的) MIME type 所組成的. 因應不同的 action, 就會使用不同的 data. 

例如:
action 是 ACTION_EDIT,  data 就應該含有要編輯的檔案的 URI (路徑).
action 是 ACTION_CALL, data 就應該含有 "tel:" + 電話號碼的 URI. 
action 是 ACTION_VIEW, data 就應該含有 "http: " + 要顯示物件的 URI.

要判斷我們所指定的原件適不適合處理傳遞來的 intent,  可以利用 (MIME) type 來判斷. 例如用來顯示圖片的原件, 就不會被用來播放聲音.

在許多情況下, type 可以從 URI 來得知. 例如看到 "content: " + URIs 就可以知道 data 是由裝置的 content provider 所控制.

Category

Category 是 intent 的一項(附加)訊息, 說明怎樣的 component 可以處理這個 intent. 例如:


Extras

Extras 是一個可以帶有許多 key-value 訊息的元件. 
這是個滿方便的元件, 在我們寫應用程式時很常使用到.

Flags

Flags 標誌常用來說明要如何執行一個 Activity (例如, 此 Activity 屬於哪個 task), 
或者用來說明這個 Activity 在執行後要如何處理 (例如, 列入最近執行的 Activities 裡) 

Intent 的解析

Intent 可以分為兩類: 

* Explicit intents: 有明確元件目標(名稱)的 intent. 
* Implicit intents: 沒有明確元件目標的 intent. (Implicit intent 通常用於啓動其他應用程式的元件)

Explicit intents 一定會呼叫特定元件名稱的元件. 而 Implicit intents 則要利用 Intent filters 來篩選出合適的元件.

篩選的考量有三個: action, data(包含 URI 跟 type), 以及  category.

Intent filters

Intent filters 寫於 AndroidManifest.xml 裡.

每一個 filter 會列出 action, data, 跟 category 的條件(不一定三個都要). 
同時通過這些條件的 intent 才會被該元件接收. 但我們也可以多建立幾個 filters, 只要 intent 過得了某一個 filter 就行了.

Action 測試

Action 的 filter 例如:

  
每個 filter 至少要有一個 action, intent 只要過得了所列出的某個 action 即可.
如果沒有給定 intent 的 action, 則 intent 會通過任何 action的測試.

Category 測試

Category 的 filter 例如:


Intent 的 category 測試也是只要過得了一個即可. 但是由於 Implicit intent 會自動加上 "android.intent.category.DEFAULT這個 category, 所以任一個想接收 Implicit intent 的元件基本上都要加上這個 category filter.

Data 測試

Data 的 filter 例如:


data 是由一個 URI 跟 一個 data type 組成. 
URI 可以分解為由 scheme, host, port, path 所構成, 形式為:

scheme://host:port/path

例如:

content://com.example.project:200/folder/subfolder/etc

則 scheme 為 "content", host 為 "com.example.project", port 是 "200", path 是 "folder/subfolder/etc", 而 host + port 又稱為 authority.

每一項屬性都是可有可無的. 但並不全部都個別獨立. 例如有 authority 就要有 scheme;  有 path, 則要有 sheme 及 authority.

如果 filter 只有  scheme, 則任一 intent 有相同 scheme 的都可以通過測試.
如果 filter 設到了 path, 則 intent 要有部分相同的 path 才能通過測試.

Type 相較於 URI, 更常用於 filters. 如果有 "*" 字號, 表示任何 subtype 皆可通過測試.
例如: "text/*" or "audio/*"

Data 測試的規則是:

a. 沒有設 data (URI or  Type) 的 intent 可以通過沒有設 data 的 filter
b. 有 URI 沒有 type 的 intent, 可以通過有設 URI 沒有設 type 的 filter, 例如: "mailto:   ", "tel:  " 就是這類.
c. 有 type 沒有 URI 的 intent, 可以通過有設 type 沒有設 URI 的 filter,
d. 有 URI 也有 type 的 intent, 在 type 的部分只要通過其中一個 type 測試即可. 
在 URI 的部分, 除了 URI 吻合這個方式外, 由於 URI 默認支持 "content: " 以及 "file: ",  所以 filter 如果只設 type, URI 是 "content: " 以及 "file: " 則也是可以過的.

常用方式

1. data 只設 type. 因為 URI 默認支持 "content: " 以及 "file: ", 所以從 content provider 讀資料的話, 不去設 URI 是常用方式


2. 如果是 browser 在搜索可用的播放軟件, 可以這樣寫



3. 初始一個 Application, 並指定為開始元件.



Intent filter 的規則不少, 
簡而言之, 如果希望外來的 Application 可以呼叫我們的 Application,
就必須寫 filter, 並且設置好 action, category, data 以避免判斷錯誤.








沒有留言:

張貼留言