Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> 必須懂的Intent Filter匹配規則

必須懂的Intent Filter匹配規則

編輯:關於Android編程

Intent簡介

Android中提供了Intent機制來協助應用間的交互與通訊,Intent負責對應用中一次操作的動作、動作涉及數據、附加數據進行描述,Android則根據此Intent的描述,負責找到對應的組件,將 Intent傳遞給調用的組件,並完成組件的調用。Intent不僅可用於應用程序之間,也可用於應用程序內部的Activity/Service之間的交互。因此,Intent在這裡起著一個媒體中介的作用,專門提供組件互相調用的相關信息,實現調用者與被調用者之間的解耦。在SDK中給出了Intent作用的表現形式為:

通過Context.startActivity() orActivity.startActivityForResult()
啟動一個Activity; 通過 Context.startService() 啟動一個服務,或者通過Context.bindService() 和後台服務交互;

通過廣播方法(比如 Context.sendBroadcast(),Context.sendOrderedBroadcast(),
Context.sendStickyBroadcast()) 發給broadcast receivers。

Intent可分為隱式(implicitly)和顯式(explicitly)兩種:

(1)顯示 Intent

即在構造Intent對象時就指定接收者,它一般用在知道目標組件名稱的前提下,一般是在相同的應用程序內部實現的,如下:

Intent intent = new Intent(MainActivit.this, NewActivity.class);
startActivity(intent );  

上面那個intent中,直接指明了接收者:NewActivity

(2)隱式 Intent

即Intent的發送者在構造Intent對象時,並不知道也不關心接收者是誰,有利於降低發送者和接收者之間的耦合,它一般用在沒有明確指出目標組件名稱的前提下,一般是用於在不同應用程序之間,如下:

Intent intent = new Intent();
intent.setAction("com.wooyun.test");
startActivity(intent);

上面那個intent,沒有指明接收者,只是給了一個action作為接收者的過濾條件。
對於顯式Intent,Android不需要去做解析,因為目標組件已經很明確,Android需要解析的是那些隱式Intent,通過解析,將Intent映射給可以處理此Intent的Activity、IntentReceiver或Service。

Intent Filter匹配規則

Intent解析機制主要是通過查找已注冊在AndroidManifest.xml中的所有IntentFilter及其中定義的Intent,最終找到匹配的Intent。在這個解析過程中,Android是通過Intent的action、type、category這三個屬性來進行匹配判斷的。一個過濾列表中的action、type、category可以有多個,所有的action、type、category分別構成不同類別,同一類別信息共同約束當前類別的匹配過程。只有一個Intent同時匹配action、type、category這三個類別才算完全匹配,只有完全匹配才能啟動Activity。另外一個組件若聲明了多個Intent Filter,只需要匹配任意一個即可啟動該組件。
例如:





(1)action的匹配規則

action是一個字符串,如果Intent指明定了action,則目標組件的IntentFilter的action列表中就必須包含有這個action,否則不能匹配。一個Intent Filter中可聲明多個action,Intent中的action與其中的任一個action在字符串形式上完全相同(注意,區分大小寫,大小寫不同但字符串內容相同也會造成匹配失敗),action方面就匹配成功。可通過setAction方法為Intent設置action,也可在構造Intent時傳入action。需要注意的是,隱式Intent必須指定action。比如我們在Manifest文件中為MyActivity定義了如下Intent Filter:


    
    

那麼只要Intent的action為“SEND”或“SEND_TO”,那麼這個Intent在action方面就能和上面那個Activity匹配成功。比如我們的Intent定義如下:

Intent intent = new Intent("android.intent.action.SEND") ;
startActivity(intent);

那麼我們的Intent在action方面就與MyActivity匹配了。
Android系統預定義了許多action,這些action代表了一些常見的操作。常見action如下(Intent類中的常量):

Intent.ACTION_VIEW
Intent.ACTION_DIAL
Intent.ACTION_SENDTO
Intent.ACTION_SEND
Intent.ACTION_WEB_SEARCH

(2)data的匹配規則

如果Intent沒有提供type,系統將從data中得到數據類型。和action一樣,同action類似,只要Intent的data只要與Intent Filter中的任一個data聲明完全相同,data方面就完全匹配成功。
data由兩部分組成:mimeType和URI
MineType指的是媒體類型:例如imgage/jpeg,auto/mpeg4和viedo/*等,可以表示圖片、文本、視頻等不同的媒體格式
uri則由scheme、host、port、path | pathPattern | pathPrefix這4部分組成

://:/[||]

例如:
content://com.wooyun.org:200/folder/etc
http://www.wooyun.org:80/search/info

Intent的uri可通過setData方法設置,mimetype可通過setType方法設置。
需要注意的是:若Intent Filter的data聲明部分未指定uri,則缺省uri為content或file,Intent中的uri的scheme部分需為content或file才能匹配;若要為Intent指定完整的data,必須用setDataAndType方法,究其原因在,setData和setType方法的源碼中我們發現:

public Intent setData(Uri data) {
    mData = data;
    mType = null;
    return this;
}
public Intent setType(String type) {
    mData = null;
    mType = type;
    return this;
}

這兩個方法會彼此互相清除對方的值(這個比較逗),即setData會把mimeType置為null,setType會把uri置為null。
下面我們來舉例說明一下data的匹配。首先我們先來看一下Intent Filter中指定data的語法:

<data android:scheme="String.“ 
          android:host=" string"="" android:port="String" android:path="String" android:pathpattern="String" android:pathprefix="String" android:mimetype="String">
    其中scheme、host等各個部分無需全部指定。

使用案例:
(1)如果我們想要匹配 http 以 “.pdf” 結尾的路徑,使得別的程序想要打開網絡 pdf 時,用戶能夠可以選擇我們的程序進行下載查看。
我們可以將 scheme 設置為 “http”,pathPattern 設置為 “.*//.pdf”,整個 intent-filter 設置為:

  
      
      
      
  

如果你只想處理某個站點的 pdf,那麼在 data 標簽裡增加 android:host=”yoursite.com” 則只會匹配 http://yoursite.com/xxx/xxx.pdf,但這不會匹配 www.yoursite.com,如果你也想匹配這個站點的話,你就需要再添加一個 data 標簽,除了 android:host 改為 “www.yoursite.com” 其他都一樣。

(2)如果我們做的是一個IM應用,或是其他類似於微博之類的應用,如何讓別人通過 Intent 進行調用出現在選擇框裡呢?我們只用注冊 android.intent.action.SEND 與 mimeType 為 “text/plain” 或 “/” 就可以了,整個 intent-filter 設置為:

  
      
      
      
 

這裡設置 category 的原因是,創建的 Intent 的實例默認 category 就包含了 Intent.CATEGORY_DEFAULT ,google 這樣做的原因是為了讓這個 Intent 始終有一個 category。

這裡寫圖片描述

(3)如果我們做的是一個音樂播放軟件,當文件浏覽器打開某音樂文件的時候,使我們的應用能夠出現在選擇框裡?這類似於文件關聯了,其實做起來跟上面一樣,也很簡單,我們只用注冊 android.intent.action.VIEW 與 mimeType 為 “audio/*” 就可以了,整個 intent-filter 設置為:<喎?/kf/ware/vc/" target="_blank" class="keylink">vcD4NCjxwcmUgY2xhc3M9"brush:java;">

這裡寫圖片描述

(3)category的匹配規則

category也是一個字符串,但是它與action的過濾規則不同,它要求Intent中個如果含有category,那麼所有的category都必須和過濾規則中的其中一個category相同。也就是說,Intent中如果出現了category,不管有幾個category,對於每個category來說,它必須是過濾規則中的定義了的category。當然,Intent中也可以沒有category(若Intent中未指定category,系統會自動為它帶上“android.intent.category.DEFAULT”),如果沒有,仍然可以匹配成功。category和action的區別在於,action要求Intent中必須有一個action且必須和過濾規則中的某幾個action相同,而category要求Intent可以沒有category,但是一旦發現存在category,不論你有多少,每個都要能夠和過濾規則中的任何一個category相同。我們可以通過addCategory方法為Intent添加category。

特別說明:


    

    

這二者共同出現,標明該Activity是一個入口Activity,並且會出現在系統應用列表中,二者缺一不可。

 

 

Intent Filter常見問題匯總

(1)path、pathPrefix、pathPattern 之間的區別

path 用來匹配完整的路徑,如:http://example.com/blog/abc.html,這裡將 path 設置為 /blog/abc.html 才能夠進行匹配;
pathPrefix 用來匹配路徑的開頭部分,拿上來的 Uri 來說,這裡將 pathPrefix 設置為 /blog 就能進行匹配了;
pathPattern 用表達式來匹配整個路徑,這裡需要說下匹配符號與轉義。
匹配符號:
” 用來匹配0次或更多,如:“a” 可以匹配“a”、“aa”、“aaa”…
“.” 用來匹配任意字符,如:“.” 可以匹配“a”、“b”,“c”…
因此 “.*” 就是用來匹配任意字符0次或更多,如:“.*html” 可以匹配 “abchtml”、“chtml”,“html”,“sdf.html”…
轉義:因為當讀取 Xml 的時候,“/” 是被當作轉義字符的(當它被用作 pathPattern 轉義之前),因此這裡需要兩次轉義,讀取 Xml 是一次,在 pathPattern 中使用又是一次。如:“” 這個字符就應該寫成 “//”,“/” 這個字符就應該寫成 “////”。

(2)查詢是否有Activity可以匹配我們指定Intent的組件

采用PackageManager的resolveActivity或者Intent的resolveActivity方法會獲得最適合Intent的一個Activity
調用PackageManager的queryIntentActivities會返回所有成功匹配Intent的Activity

(3)android.intent.action.MAIN 與android.intent.category.LAUNCHER的區別

區別一:
android.intent.action.MAIN決定一個應用程序最先啟動那個組件
android.intent.category.LAUNCHER決定應用程序是否顯示在程序列表裡(說白了就是是否在桌面上顯示一個圖標)
這兩個屬性組合情況:
第一種情況:有MAIN,無LAUNCHER,程序列表中無圖標
原因:android.intent.category.LAUNCHER決定應用程序是否顯示在程序列表裡
第二種情況:無MAIN,有LAUNCHER,程序列表中無圖標
原因:android.intent.action.MAIN決定應用程序最先啟動的Activity,如果沒有Main,則不知啟動哪個Activity,故也不會有圖標出現
所以這兩個屬性一般成對出現。
如果一個應用中有兩個組件intent-filter都添加了android.intent.action.MAIN和
android.intent.category.LAUNCHER這兩個屬性, 則這個應用將會顯示兩個圖標, 寫在前面的組件先運行。
區別二:

android.intent.category.LAUNCHER:android.intent.category.LAUNCHER決定應用程序是否顯示在程序列表裡,就是android開機後的主程序列表。
android.intent.category.HOME:按住“HOME”鍵,該程序顯示在HOME列表裡。

(4)關於隱式intent

每一個通過 startActivity() 方法發出的隱式 Intent 都至少有一個 category,就是 “android.intent.category.DEFAULT”,所以只要是想接收一個隱式 Intent 的 Activity 都應該包括 “android.intent.category.DEFAULT” category,不然將導致 Intent 匹配失敗.
比如說一個activity組件要想被其他組件通過隱式intent調用, 則其在manifest.xml中的聲明如下:


       
           
           
  

(5)於intent-filter匹配優先級

首先查看Intent的過濾器(intent-filter),按照以下優先關系查找:action->data->category

 

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved