2011年10月11日 星期二

Intent (2) - Android 新手學習筆記

上文中,介紹了元件傳遞 Intent 的方法,以及 Intent 可以包含的資訊
下面繼續來看系統如何找到適合的元件

== Intent Resolution ==

當沒有明確指明 Component name 時
Android 底層就會利用各應用程式的 manifest 中的 intent filters
來過濾可以處理此 Intent 的元件出來
所以若希望其他應用程式能透過 action 的方式來啟動你的元件
那麼就要在你的應用程式中的 manifest 設好適當的 intent filters

過濾時,只會用到上面的三種資訊
action
date (both URI and data type)
category

== Intent filters ==

一般來說 Intent filter 的設定,是在 manifest 中加入 <intent-filter> 元素
並不會在 Java Code 中來做此設定
但有一個例外,broadcast receiver 可以用 Context.registerReceiver() 來動態設定

每一個 filter 可以有三種子元素,對應到 Intent 的 action、data、category 三種資訊
在過濾時,就是用這三種子元素的內容來比對
必需三個子元素的條件都符合 Intent 的資訊時,才表示此 filter 滿足這個 Intent

一個元件可以設定多個 Intent filter
當有一個 Intent 需求時,只要元件的任何一個 filter 能滿足這個需求
就表示這個元件可以處理此 Intent 了

* Action test
<intent-filter> 下可以用 <action> 來定義此元件的 action 過濾條件(即可以處理哪些 action)
例如
<intent-filter . . . >
    <action android:name="com.example.project.SHOW_CURRENT" />
    <action android:name="com.example.project.SHOW_RECENT" />
    <action android:name="com.example.project.SHOW_PENDING" />
    . . .</intent-filter>

這裡的 android:name 屬性值可以是自訂的名稱,也可以是標準的名稱
一個 filter 至少要有一個 <action> 設定,否則它就無法接受任何 action
Intent 物件中所指定的 action 只要符合 filter 中的任何一個 action
就表示通過了此 filter 的 action test,也就是此元件可以處理這個 Intent 的 action

* Category test
<intent-filter> 下可以用 <category> 來定義此元件的 category 過濾條件(即可以處理哪些 category)
例如
<intent-filter . . . >
    <category android:name="android.intent.category.DEFAULT" />
    <category android:name="android.intent.category.BROWSABLE" />
    . . .</intent-filter>

一個 filter 下可以有多個 category 設定,但一個 Intent 物件也可以指定多個 category 資訊
這裡的比對原則是 Intent 物件中的所有 category 都能在該 filter 中找到時才算是符合條件
也就是只要 Intent 物件中的任何一個 category 在該 filter 中找不到
就不通過此 filter 的 category test

一般在用 startActivity() 時所傳入的 Intent 並沒有強制一定要加 category
但 Android 會自己幫它加上一個 Intent.CATEGORY_DEFAULT 資訊
所以 filter 中至少要有一個 android.intent.category.DEFAULT
才有可能處理 Implicit Intent
註:
當 filter 有設定 android.intent.action.MAIN 及 android.intent.category.LAUNCHER 時
可以不用再設 android.intent.category.DEFAULT
因為 LAUNCHER 這個 category
表示要將此 Activity 列在使用者的應用程式清單中
以讓使用者點選進入
所以它應該不是用來處理 Implicit Intent 的

* Data test

<intent-filter> 下可以用 <data> 來定義此元件的 data過濾條件(即可以處理哪些 data)
例如
<intent-filter . . . >
    <data android:mimeType="video/mpeg" android:scheme="http" . . . />
    <data android:mimeType="audio/mpeg" android:scheme="http" . . . />
    . . .</intent-filter>

可以設定多個 data,也可以不設定任何 data 資訊
每個 data 可以包含 MIME media type 及 URI 兩種資訊
URI 的部份是由四個屬性所組成:
android:scheme
android:host
android:port
android:path

對應 URI 的格式為

scheme://host:port/path

如果 host 沒有指定,則 port 也會被忽略
如果有指定 host 及 port,則 scheme 也必須指定
如果有指定 path,則 scheme、host、port 也都必須指定
所以應該只有三種設定格式

scheme
scheme + host + port
scheme + host + port + path

filter 在比對時只會比對 filter 中有設定的部份
例如,若 filter 只有指定 scheme
則 Intent 中的 URI 只要有相同的 scheme
不管 URI 中的 host port path 等內容是什麼,都算符合
其他以此類推
比較不同的是,path 可以用萬用字元

mimeType 屬性也可以在 "/" 之後的部份使用萬用字元
例如 "text/*" 或 "audio/*"

filter 對 type 及 URI 的比對原則為:
(1) 如果 Intent 中沒有指定 type 及 URI,則只有同樣沒有設定 type 及 URI 的 filter 才符合
(2) 如果 Intent 中只有指定 URI 而沒有指定 type,且從 URI 中無法推斷是哪一種 type (例如 URI 是 mailto: 或 tel: ),則只有沒有設定 type 且有設定相符的 URI 的 filter 才符合
(3) 如果 Intent 中只有指定 type 而沒有指定 URI,則只有沒有設定 URI 且有設定相符的 type 的 filter 才符合
(4) 如果 Intent 中 URI 及 type 都有指定,或是沒有直接指定 type,但可以從 URI 的推斷出 type,則必須 filter 中也有設定相符的 type,且還有指定相符的 URI 才符合,不過有個例外,如果 Intent 的 URI 是 content: 或 file: 且 filter 只有設定 type 沒有設定 URI,這樣也符合,因為當 filter 只有設定 type 沒有設定 URI 時,預設會將 filter 視為支援 content: 及 file: 這兩種 URI

所以由上述 (3) 及 (4),也可以由 filter 的角度再整理出一點
當 filter 只有設定 type 時,它可符合兩種 Intent
(1) 具有相同 type 且沒有 URI 的 Intent
(2) 具有相同 type 且 URI 是 content: 或 file:

Intent (1) - Android 新手學習筆記
Intent (3) - Android 新手學習筆記

沒有留言:

張貼留言

廣告訊息會被我刪除

Related Posts with Thumbnails