回顧與總結:
- Intent能啓動Activity,Service,BroadcastReceiver三大系統組件
- 指定Intent的Component屬性就是顯性定義Intent,只要爲其賦予Component對象就行了。沒有指定的即爲隱性定義Intent,此時Intent所啓動的組件能否啓動取決於組件的<intent-filter>元素的配置:只要某個組件能滿足的要求大於或等於Intent所指定的要求 ,那麼該Intent就能啓動
//第一種方式顯示聲明Intent ComponentName comp = new ComponentName(ThisClass.this,SecondClass.class); Intent intent = new Intent(); intent.setComponent(intent); //第二種方式顯示聲明Intent Intent intent = new Intent(ThisClass.this,SecondClass.class);
- 指定Intent的Component屬性即是顯性聲明intent明確要啓動哪個組件,被啓動組件幾乎無需配置<intent-filter>元素。此時,<intent-filter>中的Action,Category,Data,Type,Extra,Flag對於顯性聲明的Intent無效。
- Action代表該Intent要完成的一個操作,而Category則是對Action 的補充說明類別信息。一個Intent只能攜帶一個Action,卻能攜帶多個Category。但intent-filter能配置多個Action元素且至少有一個默認的Category,當某個Intent攜帶的Action屬性被多個組件響應時,程序會彈出請求畫面交給用戶選擇
- Activity,service,receiver的子元素,能配置的要素有:0-N個action,0-N個category,0-1個data
- 指定Action,Category調用系統Activity
- Data,Type,Extra,Flag屬性的設置
- 使用Intent創建Tab頁面
- Intent一旦發出,Android都會準確找到相匹配的一個或多個Activity,Service或者BroadcastReceiver作響應。所以,不同類型的Intent消息不會出現重疊,即Broadcast的Intent消息只會發送給BroadcastReceiver,而決不會發送給Activity或者Service。由startActivity()傳遞的消息也只會發給Activity,由startService()傳遞的Intent只會發送給Service。
- 註冊的action的名字爲.intent.action.YOUR_ACTION_NAME。(試驗:如果不採用package-name,調用時會出現找不到Activity的異常)經測試,沒有這個異常。
- 在intent中傳遞的不是reference(指針),而是copy一份,我們修改對象,並不會影響已經copy進intent中bundle的數據,這點需要非常注意。
- activity的intent-filter中可以有多個category描述,其中CATEGORY_DEFAULT表示可以使用implicit intent調用,當我們增加此項聲明後,本應用就出現在匹配的activity列表中。同樣,對於通過action name來調用的,不指定包名和類名的,也屬於implicit intent,同樣需要進行CATEGORY_DEFAULT的聲明,否則會出現ActivityNotFoundException的錯誤。如果activity沒有在intent
fliter中設置爲CATEGORY_DEFAULT,我們可以用PackageManager獲取匹配的activities的信息,分析後得到確切的包名和類名,通過explicit的方式喚起該activity。
此外Android說如果從launcher screen喚起時不需要DEFAULT,也就是此時acitivty只需MAIN和LAUNCHER,當然我們也可以DEFAULT設上。Android在DEFAULT上似乎有些繁雜,簡單說如果我們不希望App被其他App通過implicit調用,我們就不要設置DEFAULT。
什麼是Intent
Intent直譯“意圖”,是對操作執行的抽象描述。主要解決Android應用的各項組件之間的通訊。Intent負責對應用中一次操作的動作、動作涉及數據、附加數據進行描述,Android則根據此Intent的描述,負責找到對應的組件,將 Intent傳遞給調用的組件,並完成組件的調用。因此,Intent在這裏起着一個媒體中介的作用,專門提供組件互相調用的相關信息,實現調用者與被調用者之間的解耦。總的來說:Intent具有組件激活和數據攜帶的功能。
Intent的構成
Intetn對象的組成:Action,Data,Category,Extras,Flags,Component name
Action:說明要執行的操作,是字符串常量,更多Action可以到幫助文檔Intent類找到。用戶也可以自己定義自己的Action常量。通常使用setAction()和getAction()來設置
注意的點:一個Intent最多隻能設置一個Action常量,啓動的組件的Intent-filter能配置多個Action常量
常用的Action:
ACTION_CALL |
activity |
啓動一個電話. |
ACTION_EDIT |
activity |
顯示用戶編輯的數據. |
ACTION_MAIN |
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 |
改變時區警告. |
Data:是執行動作的URI和MIME類型,不同的動作有不同的數據規格。即通常來爲Action屬性提供操作的數據。通俗的講:Action是ACTION_EDIT時,數據域將是文檔的URI;Action是ACTION_CALL時,數據域是 tel: URI ,帶有要撥打的電話號碼;如果Action是 ACTION_VIEW,則數據域是http: URI。匹配到Intent的組件知道Intent所攜帶的數據類型是很重要的。因爲不可能叫一個文本編輯的組件去播放視頻。
注意的點:
- Data屬性接受一個Uri對象,Uri對象用滿足如下的字符串來表示:scheme://host:port/path 例如:content://com.android.contacts:8080/contacts/1
- Type屬性即MIME類型,指定該Data所指定的Uri對應的MIME類型,這種MIME類型可以是任何自定義的MIME類型,只要符合abc/xyz格式的字符串就行了
- 數據類型也可以顯式指定,比如setData()方法指定數據爲URI,setType() 指定爲MIME type,setDataAndType() 指定它既爲URI又爲MIME type。讀取的時候URI用getData(),MIME type用getType()。但要注意如果分別設置Data屬性,Type屬性會相互覆蓋。
MIME類型有2種形式:
1.1 單個記錄的格式: vnd.android.cursor.item/vnd.yourcompanyname.contenttype,如:content://com.example.transportationprovider/trains/122(一條列車信息的uri)的MIME類型是vnd.android.cursor.item/vnd.example.rail
1.2 多個記錄的格式:vnd.android.cursor.dir/vnd.yourcompanyname.contenttype,如:content://com.example.transportationprovider/trains (所有列車信息)的MIME類型是vnd.android.cursor.dir/vnd.example.rail
- 目標組件的<data>子元素只指定了android:scheme,android:host,android:port,android:path,那麼Intent的Data屬性的scheme,host,port,path要全部對應相同的屬性值纔可啓動
- 目標組件的<data>子元素只指定了android:scheme,android:host,android:path,那麼只要Intent的Data屬性的scheme,host,path對應相同的屬性值就能啓動了
- 目標組件的<data>子元素只指定了android:scheme,android:host,android:port,那麼只要Intent的Data屬性的scheme,host,port對應相同的屬性值就能啓動了
- 目標組件的<data>子元素只指定了android:scheme,android:host,那麼只要Intent的Data屬性的scheme,host,對應相同的屬性值就能啓動了
- 目標組件的<data>子元素只指定了android:scheme,那麼只要Intent的Data屬性的scheme對應相同的屬性值就能啓動了
- 另外注意的是如果沒有指定android :host屬性,那麼android:port,android:path,是起不到作用的。總的來說:Intent攜帶的Data屬性要大於或等於data元素配置的要求就行了。
- 一個Intent能攜帶多個Category,Intent-filter要配置至少一個Category屬性(就算Intent沒添加Category屬性,也應該在intent-filter配置一個Intent.CATEGORY_DEFAULT屬性)
- 確定了component name,即顯性定義了Intent,程序將不會根據Intent 的屬性去尋找合適的組件。
Intent解析機制
application package的信息)來查找能處理這個Intent的component。在這個解析過程中,Android是通過Intent的action、type、category這三個屬性來進行判斷的,判斷方法如下:
1.1 如果Intent指明定了action,則目標組件的IntentFilter的action列表中就必須包含有這個action,否則不能匹配;
1.2 如果Intent沒有提供type,系統將從data中得到數據類型。和action一樣,目標組件的數據類型列表中必須包含Intent的數據類型,否則不能匹配。
1.3 如果Intent中的數據不是content:類型的URI,而且Intent也沒有明確指定type,將根據Intent中數據的scheme(比如 http:或者mailto:)進行匹配。同上,Intent 的scheme必須出現在目標組件的scheme列表中。
1.4 如果Intent指定了一個或多個category,這些類別必須全部出現在組建的類別列表中。比如Intent中包含了兩個類別:LAUNCHER_CATEGORY和ALTERNATIVE_CATEGORY,解析得到的目標組件必須至少包含這兩個類別。