Android Intent和IntentFilter詳解

 

 

Intent用於啟動Activity, Service, 以及BroadcastReceiver三種組件, 同時還是組件之間通信的重要媒介.

使用Intent啟動組件的優勢
1, Intent為組件的啟動提供瞭一致的編程模型. 無論想要啟動的組件是Activity, Service, 還是BroadcastReceiver, 都可以使用Intent封裝啟動的意圖.
2, 在某些時候, 應用程序隻是想啟動具有某種特征的組件, 並不想和某個特定的組件耦合. 使用Intent可以方便的達到這種高層次解耦的目的.

Intent的Component屬性
Intent對象的setComponent(ComponentName comp)方法用於設置Intent的Component屬性. ComponentName包含如下幾個構造器:
ComponentName(String pkg, String cls)
ComponentName(Context pkg, String cls)
ComponentName(Context pkg, Classcls)
由以上的構造器可知, 創建一個ComponentName對象需要指定包名和類名–這就可以唯一確定一個組件類, 這樣應用程序即可根據給定的組件類去啟動特定的組件. 例如:
ComponentName comp = new ComponentName(FirstActivity.this, SecondActivity.class);
Intent intent = new Intent();
intent.setComponent(comp);
以上三句代碼創建瞭一個intent對象, 並為其指定瞭Component屬性, 完全等價於下面的代碼:
Intent intent = new Intent(FirstActivity.this, SecondActivity.class);
除瞭使用setComponent() 之外, 還可以使用setClass(), setClassName()來顯式指定目標組件, 還可以調用getComponent()方法獲得Intent中封裝的ComponentName對象.
當程序采用這種形式啟動組件時, 在Intent中明確的指定瞭待啟動的組件類, 此時的Intent屬於顯式intent, 顯式Intent應用場合比較狹窄, 多用於啟動本應用中的component, 因為這種方式需要提前獲知目標組件類的全限定名. 而隱式Intent則通過Intent中的action, category, data屬性指定目標組件需要滿足的若幹條件, 系統篩選出滿足所有條件的component, 從中選擇最合適的component或者由用戶選擇一個component作為目標組件啟動.
如果Intent中指定瞭ComponentName屬性, 則Intent的其他屬性將被忽略.

Intent的Action屬性
action屬性是一個字符串, 代表某一種特定的動作. Intent類預定義瞭一些action常量, 開發者也可以自定義action. 一般來說, 自定義的action應該以application的包名作為前綴, 然後附加特定的大寫字符串, 例如cn.xing.upload.action.UPLOAD_COMPLETE就是一個命名良好的action.
Intent類的setAction()方法用於設定action, getAction()方法可以獲取Intent中封裝的action.
以下是Intent類中預定義的部分action:
ACTION_CALL–目標組件為activity, 代表撥號動作;
ACTION_EDIT–目標組件為activity, 代表向用戶顯示數據以供其編輯的動作;
ACTION_MAIN–目標組件為activity, 表示作為task中的初始activity啟動;
ACTION_BATTERY_LOW–目標組件為broadcastReceiver, 提醒手機電量過低;
ACTION_SCREEN_ON–目標組件為broadcast, 表示開啟屏幕.

Intent的Category屬性
category屬性也是一個字符串, 用於指定一些目標組件需要滿足的額外條件. Intent對象中可以包含任意多個category屬性. Intent類也預定義瞭一些category常量, 開發者也可以自定義category屬性.
Intent類的addCategory()方法為Intent添加Category屬性, getCategories()方法用於獲取Intent中封裝的所有category.
以下是Intent類中預定義的部分category:
CATEGORY_HOME–表示目標activity必須是一個顯示home screen的activity;
CATEGORY_LAUNCHER–表示目標activity可以作為task棧中的初始activity, 常與ACTION_MAIN配合使用;
CATEGORY_GADGET–表示目標activity可以被作為另一個activity的一部分嵌入.

Intent的Data屬性
data屬性指定所操作數據的URI. data經常與action配合使用, 如果action為ACTION_EDIT, data的值應該指明被編輯文檔的URI; 如果
action為ACTION_CALL, data的值應該是一個以tel:開頭並在其後附加號碼的URI; 如果action為ACTION_VIEW, data的值應該是一個以http: 開頭並在其後附加網址的URI…
Intent類的setData()方法用於設置data屬性, setType()方法用於設置data的MIME類型, setDataAndType()方法可以同時設定兩者. 可以通過getData()方法獲取data屬性的值, 通過getType()方法獲取data的MIME類型.

Intent的Extra屬性
通過Intent啟動一個component時, 經常需要攜帶一些額外的數據過去. 攜帶數據需要調用Intent的putExtra()方法, 該方法存在多個重載方法, 可用於攜帶基本數據類型及其數組, String類型及其數組, Serializable類型及其數組, Parcelable類型及其數組, Bundle類型等. Serializable和Parcelable類型代表一個可序列化的對象
, Bundle與Map類似,可用於存儲鍵值對.

Intent的Flag屬性
flag屬性是一個int值, 用於通知android系統如何啟動目標activity, 或者啟動目標activity之後應該采取怎樣的後續操作. 所有的flag都在Intent類中定義, 部分常用flag如下:
FLAG_ACTIVITY_NEW_TASK–通知系統將目標activity作為一個新task的初始activity;
FLAG_ACTIVITY_NO_HISTORY–通知系統不要將目標activity放入歷史棧中;
FLAG_FROM_BACKGROUND–通知系統這個Intent來源於後臺操作, 而非用戶的直接選擇…

IntentFilter類
IntentFilter類表示Intent過濾器, 大部分情況下, 每一個component都會定義一個或多個IntentFilter, 用於表明其可處理的Intent.
一般來說, component的IntentFilter應該在AndroidManifest.xml文件中定義.
定義的方法: 在, , 元素中增加一個或多個子元素. 如:

IntentFilter與隱式Intent
android系統處理隱式Intent時, 會比較Intent和IntentFilter的action, data, category屬性, 如果以上3個屬性全都相符的話, 則IntentFilter所屬的component就可以作為目標組件的候選(存在多個符合條件的component時).
1. 測試action屬性. intent最多隻能定義1個action, 而filter可以定義1個或多個action.
通過action測試的條件為: filter定義瞭intent的action. 例如intent的action為android.intent.action.MAIN, 則定義瞭android.intent.action.MAIN這個action的filter都能通過action測試(當然, filter還可以包含更多額外的action).
如果filter沒有定義action, 則這個filter將阻塞所有intent. 如果intent沒有定義action, 那麼隻要filter定義瞭action就可以通過action測試.
2. 測試category屬性. intent可以任意多個category, filter也可以任意個category. 通過category測試的條件為: filter定義瞭intent的所有category. 例如intent定義瞭android.intent.category.DEFAULT和cn.xing.intent.category.UPLOAD這2個category, 則定義瞭以上2個category屬性的filter才能通過測試(當然, filter還可以包含更多額外的category).
根據上面的規則, 如果一個intent沒有定義category, 則所有filter都可以通過category測試. 但是有一種例外: 以startActivity(intent)方式啟動一個activity時, 系統為會intent增加一個值為android.intent.category.DEFAULT的category, 這就意味著每一個期望通過category測試的activity, 都要在其filter中定義android.intent.category.DEFAULT(除瞭作為程序入口的activity).
3. 測試data屬性. intent最多隻能定義1個data, filter則可以定義多個data.
通過data測試的條件為:
a. 如果intent沒有指定data和data type, 則隻有沒有定義data和date type的filter才能通過測試;
b. 如果intent定義瞭data沒有定義data type, 則隻有定義瞭相同data且沒有定義date type的filter才能通過測試;
c. 如果intent沒有定義data卻定義瞭data type, 則隻有未定義data且定義瞭相同的data type的filter才能通過測試;
d. 如果intent既定義瞭data也定義瞭data type, 則隻有定義瞭相同的data和data type的filter才能通過測試.
data屬性是一個URI, URI中包含scheme, host, post和path, 典型的URI為:
scheme://host:port/path
scheme, host, post和path都是可選的. 比較2個data時, 隻比較filter中包含的部分. 比如filter的一個data隻是指定瞭scheme部分, 則測試時隻是比較data的scheme部分, 隻要兩者的scheme部分相同, 就視為相同的data.

發佈留言