android學習日記——Intent與IntentFilter

回顧與總結:

  • 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

在AndroidManifest.xml爲組件聲明Data、Type屬性時通過<data>元素來配置,但要注意的是Intent的Type屬性要完全匹配對應組件在<Intent-filter>元素中的<data>元素的<mimeType>屬性的設置,組件才能啓動。但是Data屬性的匹配卻不同,不要求全部匹配。
  • 目標組件的<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元素配置的要求就行了。
Category:也是一個字符串常量,用於爲Action 增加額外的附加類別信息,API文檔中的Intent也定義了很多Category常量。與category相應的方法有添加addCategory()、移除removeCategory() 和獲取所有category getCategories() 。
注意的點:
  • 一個Intent能攜帶多個Category,Intent-filter要配置至少一個Category屬性(就算Intent沒添加Category屬性,也應該在intent-filter配置一個Intent.CATEGORY_DEFAULT屬性)
Extras:傳遞給Intent的額外數據,以Bundle的形式定義,Bundle就像Map一樣封裝着一些鍵值對。通常用於在多個Action之間進行數據交換,Intent對象有一系列的putXXX()函數用於放入各種數據類型,相應的也有一系列的getXXX()函數用於讀取數據。
  
Flags:各種類型的Flag。很多是用來指定Android系統如何啓動activity,還有啓動了activity後如何對待它。所有這些都定義在Intent類中。Intent可通過addFlags()來添加

component name:組件名稱,即要處理這個Intent 的組件名稱,由componentName封裝。組件名稱通過 setComponent(),setClass(),setClassName()設置,通過getComponent()獲取。
  • 確定了component name,即顯性定義了Intent,程序將不會根據Intent 的屬性去尋找合適的組件。

Intent解析機制

Intent解析機制主要是通過查找已註冊在AndroidManifest.xml中的所有<intent-filter>及其中定義的Intent,通過PackageManager(注:PackageManager能夠得到當前設備上所安裝的
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,解析得到的目標組件必須至少包含這兩個類別。


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