Intent 和 Intent Filter

Android 應用程序中有三大核心組件: Activity, Service, Broadcast Receiver 都是通過被稱之爲意圖的消息運行。Intent messaging is a facility for late run-time binding between components in the same or different applications. 意圖本身一個 Intent 對象,它保存了對要執行操作的抽象描述—對於broadcasts來說,則表示對已經發生並且正要報告的操作。對這下三種組件,發送intents分別有不同的機制。

  • 傳遞一個Intent對象到 Context.startActivity(intent) 或者 Activity.startActivity ForResult(int) 去運行一個Activity(可以在通過此方式啓動後的Activity中調用 Activity.setResult() 設置結果參數,該參數將會在啓動當前activity的activity中被接收---可以通過onActivityResult(int requestCode, int resultCode, Intent data) 接收)
  • 傳遞一個Intent對象到 Context.startService(intent) 去啓動一個service 或者 傳遞一個新的指令到正在運行的service中。另外,還可以通過 Context.bindService(intent) 去綁定一個Service。(在調用組件和目標Service 建立一個連接)
  • 傳遞一個Intent對象到 任何一個broadcast methods (如: Context.sendBroadcast() , Context.sendOrderedBroadcast(), Context.sendStickyBroadcast() ) 該intent將被傳遞給所有已經被註冊的broadcast receiver中。

在以上的三種情況下,當Intent被傳遞出後,Android系統會找到適合的activity,service,或者是多個broadcast receiver去響應這個intent。,這三種情況不會存在重疊的部分,它們相互獨立,互不干擾。(調用Context.startActivity()後 intent只會被相應的activity接收到)

 


Intent Object

一個Intent對象是一個信息包。它包含了要接收此Intent的組件需要的信息(例如需要的動作和動作需要的信息)和 android 系統需要的信息(要處理此Intent的組件的類別和怎樣啓動它)

總的來說,Intent Object 主要包括以下信息:

Component name

處理Intent 的組件名稱。此字段是一個 ComponentName object---它是目標的組件的完整限定名(包名+類名) 例如: “com.android,.test.TestActivity” .

該字段是可選的。如果設置了此字段,那麼 Intent Object 將會被傳遞到這個組件名所對應的類的實例中。 如果沒有設置,Android 會用 Intent object 中的其它信息去定位到一個合適的目標組件中。 (稱之爲 : Intent 解析。。。這個稍後會講到)

設置Component name 可以通過 setComponent() , setClass() 或者 setClassName()進行設置。 可以通過 getComponent() 進行讀取

動作(Action)

一個字符串,代表要執行的動作。 -- 或者,對於 broadcase intents 來說,表示正在發生,並且被報告的動作。Intent 類中 定義了許多動作常量。 如下:

Constent( 常量)

Target Component (目標組件)

Action (動作 )

ACTION_CALL

activity

初始化一個電話呼叫

ACTION_EDIT

activity

顯示用戶要編輯的數據

ACTION_MAIN

activity

將該Activity作爲task的第一個Activity ,沒有數據輸入,也沒有數據返回

ACTION_SYNC

activity

在設備上同步服務器上的數據

ACTION_BATTERY_LOW

broadcast receiver

電量不足的警告

ACTION_HEADSET_PLUG

broadcast receiver

耳機插入設備,或者從設備中拔出

ACTION_SCREEN_ON

Broadcast receiver

屏幕已經點亮

ACTION_TIMEZONE_CHANGED

Broadcast receiver

時區設置改變

你也可以定義自己的 action strings 來激活組件。自定義的action 應該包含包名作爲前綴: 例如"com.example.project.SHOW_COLOR".

Action 很大程度上決定 Intent餘下部分的結構。 ---- 特別是:data 和 extras 兩個字段。就像一個方法的方法名通常決定了方法的參數和返回值。 基於這個原因,應該給action 命名一個儘可能明確的名字。 可以通過 setAction() 設置action,通過 getAction() 進行獲取.

Data

Data屬性有兩部分構成: 數據URI 和 數據MIME type 。 action的定義往往決定了data該如何定義。 例如: 如果 一個Intent的 action 爲 ACTION_EDIT 那麼它對應的data 應該包含待編輯的數據的URI . 如果一個action 爲:ACTION_CALL ,那麼data 應該爲 tel: 電話號碼的URI . 類似的, 如果action 爲 ACTION_VIEW 那麼data 應該爲: http: URI , 接收到的activity 將會下載並顯示相應的數據。

當一個Intent 和 有能力處理此Intent的組件進行匹配時, 除了 data的URI以外,瞭解data的類型(MIME Type)也很重要。 例如: 一個顯示圖片的組件 不應該去播放聲音文件。

許多情況下,data type 可以從URI中推測出。 尤其是: URI = content: URIs這時候數據通常是位於本設備上而且是由某個content provider來控制的。即便如此,我們仍然可以明確的在 Intent object上設置一個 data type. setData() 方法只能設置URI, setType() 設置MIME type, setDataAndType() 可以對二者都進行設置, 獲取URI 和 data type 可分別調用 getData() 和 getType() 方法。

Category

一個字符串, 包含了處理該Intent的組件的種類信息, 起着對action的補充說明作用.

一個Intent對象可以有任意多個 category。和action 一樣, 在Intent class 中也定義了幾個 category 常量。。 如下:

Constant

Meaning

CATEGORY_BROWSABLE

目標Activity可以使用瀏覽器顯示數據

CATEGORY_GADGET

The activity can be embedded inside of another activity that hosts gadgets.

該activity可以被包含在另外一個裝載小工具的activity中.

CATEGORY_HOME

The activity displays the home screen, the first screen the user sees when the device is turned on or when the HOME key is pressed.

CATEGORY_LAUNCHER

The activity can be the initial activity of a task and is listed in the top-level application launcher.

可以讓一個activity出現在launcher

CATEGORY_PREFERENCE

The target activity is a preference panel.

該activity是一個選項面板

addCategory() 添加一個 category

removeCategory() 刪除一個 category()

getCategorys() 獲取所有的category()

Extras

爲鍵-值對形式的附加信息. 例如ACTION_TIMEZONE_CHANGED的intent有一個"time-zone"附加信息來指明新的時區, 而ACTION_HEADSET_PLUG有一個"state"附加信息來指示耳機是被插入還是被拔出.

intent對象有一系列put...()和set...()方法來設定和獲取附加信息. 這些方法和Bundle對象很像. 事實上附加信息可以使用putExtras()和getExtras()作爲Bundle來讀和寫.

Flags

有各種各樣的標誌,許多指示Android系統如何去啓動一個活動(例如,活動應該屬於那個任務)和啓動之後如何對待它(例如,它是否屬於最近的活動列表)。所有這些標誌都定義在Intent類中。

 

 


Intent Resolution

Intent 有兩種形式:

l 顯示意圖指定一個目標組件通過其name( Component name field), 由於組件名稱通常不會被其它應用程序的開發者知道。所以,顯示意圖通常用在應用程序內部消息。----如:一個Activity 啓動一個從屬的service或者啓動另一個activity

l 隱式意圖不指定目標組件名稱(component name 是空的)隱式意圖通常用於去激活其它應用程序的組件

Android 傳遞了一個顯示意圖給一個被指定的目標類的實例 。被傳遞的 intent object 只是定義了component name -- 它決定了將會有那個組件去處理這個intent。

針對隱式意圖需要不同的策略。在缺乏一個被指定的target的情況下,android系統必須找到最適合的組件去處理這個intent ---- 一個單一的activity 或者 service 去執行一個請求動作或者一組broadcase receiver 去響應廣播通知.

它通過將intent 對象中的內容 和 意圖過濾器(intent filters)進行比較。android系統根據intent filter打開可以接收intent的組件. 如果一個組件沒有intent filter, 那麼它只能接受顯式intent. 如果有, 則能同時接受二者.。

Only three aspects of an Intent object are consulted when the object is tested against an intent filter:

當一個intent和intent過濾器進行比較時只會考慮以下三方面:

action 
data (both URI and data type) 
category

Intent filters

要告訴android系統哪個intent它們可以處理,activities,services,和 broadcast receivers 必須設置一個或者多個intent過濾器。每個過濾器描述了組件的一種能力,它過濾掉不想要的intent,留下想要的。顯示意圖則不用考慮這些。

一個過濾器中包含 一個Intent object 中的三個屬性 action,data,catrgory 。一個隱式意圖必須要通過這三項測試才能傳遞到 包含該過濾器的組件中。

測試1:Action test

<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>

如實例所示,當一個intent對象只能命名一個單一的action,一個過濾器則可以列出多個action。這個列表也可以是空的, 一個過濾器必須包含一個 <action> element ,否則它將阻止所有的intents要通過這個測試,在intent被指定的action必須匹配在過濾器中所列的action的其中之一。如果一個intent對象或者過濾器沒有指定action。 結果如下 :

l 如果一個filter 沒有指定任何action ,那麼則沒有任何intent會被匹配。所以,所有的intent將不會通過此測試。

l 另一方面,如果一個intent對象沒有指定任何action,那麼將自動通過此測試—只要這個過濾器中有至少一個action

測試2:Category test

<intent-filter . . . >
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
    . . .
</intent-filter>

要通過category測試, Intent對象中包含的每個category必須匹配filter中的一個。Filter可以列出額外的category,但是不能漏掉 intent 對象包含的任意一個category。

原則上,一個沒有任何categorys的 Intent object 將總是通過此測試。大多數情況下是正確的。然而,也有例外,android對待所有傳入 startActivity() 中的隱式視圖,都認爲它們至少包含了一個 category --- "android.intent.category.DEFAULT". . 因此,希望接收這些隱式意圖的activities必須在在它們的 intent filters 中包含”android.intent.category.DEFAULT” ..有(對於包含"android.intent.action.MAIN" and "android.intent.category.LAUNCHER"的filter 則是例外。因爲它們標記了此activity開啓了一個新的task 和 將出現在 auncher screen。它們也可以包含“com.intent.category.DEFAULT”,但沒必要)

測試3:Data test

類似於action, categories, data也是 intent filter 中的一個子節點, 可以設置多個 data節點,也可以一個不設置。

如下圖:

<intent-filter . . . >
<data android:mimeType="video/mpeg" android:scheme="http" . . . />
<data android:mimeType="audio/mpeg" android:scheme="http" . . . />
    . . .
</intent-filter>

每個< data > 元素可以指定一個 URI 和 一個 data type (MIME media type) . URI 有以下幾個屬性組成 : schema, host,port,path

Schema://host:port/path

例如:

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

在上例中 schema 是 content: host: com.example.project

Port: 200 Path: folder/subfolder/etc

主機 host 和 port 一起組成了URI authority,如果沒有指定 host,那麼port將被忽略。

<data>節點中的屬性都是可選的,但它們並非相互獨立。要使一個authority 有意義,必須要指定 scheme 。 要是 path 有意義, scheme 和 authority(host:port) 必須指定。

當Intent對象中的URI 和 intent filter 進行比較時,它只會進行部門比較。 例如: 如果一個 filter 只指定了一個scheme , 那麼所有包含該scheme的URI都會匹配。 如果一個filter只指定了 scheme 和 authority ,沒有path, 那麼所有包含此scheme 和 authority 將會匹配。如果一個filter指定了一個scheme,authority, 和一個path, 那麼只有包含同樣的 scheme,authoritym,path會匹配。 但是,對於path,我們可以使用通配符進行部門匹配。

<data>節點的 type 屬性指定了 data的MIME type。 它比在filter中的URI 更常見 intent對象和filter都可以使用 “*” 通配符作爲子類型 – 例如: "text/*" or "audio/*"--- 表示所有子類型都匹配。

data test 會將 intent對象中的URI 和 data type 與filter指定的都進行比較。 規則如下:

a) 如果一個intent 沒有指定URI 和 data type , 那麼如果filter中也是同樣,則通過測試。

b) 如果一個iintent 有URI 但是沒有 data type(或者是data type不能從uri中推斷出來 ) 只能通過這樣的filter: uri匹配, 並且不指定類型. 這種情況限於類似mailto:和tel:這樣的不指定實際數據的uri.

c) 如果一個intent 包含 data type 但是沒有 uri ,那麼 filter中列出相同的data type 並且沒有指定URI 則通過測試。

d) 如果一個intent包含一個URI 和data type (或者data type 可以從URI中推斷出來),那麼filter列出的有相同data type ,intent對象的uri要麼和filter中的uri匹配,要麼intent的uri爲 content: or file: 並且filter不指定uri

如果一個Intent 可以通過多個activity或者filter的filter,那麼用戶將會被詢問需要激活哪個組件。 如果一個都沒有的話,將會拋出異常。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章