Intent-Filter匹配規則

Intent-Filter匹配規則
    只有action、data、category三方都匹配,Intent纔算是匹配成功,進而才能啓動相應的Activity。一個Activity若聲明瞭多個 Intent-Filter,只需要匹配任意一個即可啓動該Activity。

(1)action的匹配規則
    action 是一個字符串,系統預定義了一些 action,同時我們也可以在應用中定義自己的 action。action 的匹配規則是 Intent 中的 action 必須能夠和 Intent-Filter中的action 匹配(action 的字符串值完全一樣,action 字符串區分大小寫), 一個 Intent-Filter 中可聲明多個action,Intent 中的 action 與其中的任一個 action 在字符串形式上完全相同即可匹配成功。

   需要注意的是,隱式Intent必須指定action(如不指定action則必須指定data或mimetype。這種情況下,只要Intent-Filter 至少含有一個action就可以匹配),如果沒有指定,則匹配失敗。比如我們在Manifest文件中爲MyActivity定義瞭如下 Intent-Filter:
<intent-filter>
     <action android:name="android.intent.action.SEND"/>
     <action android:name="android.intent.action.SEND_TO"/>
</intent-filter>
    那麼只要Intent的action爲“SEND”或“SEND_TO”,那麼這個Intent在action方面就能和上面那個Activity匹配成功。比如我們的Intent定義如下:
Intent intent = new Intent("android.intent.action.SEND")
(2)category的匹配規則
    category 是一個字符串,系統預定義了一些category ,同時我們也可以在應用中定義自己的category 
    與action不同,Intent 中的 category 必須都在 Intent-Filter中出現纔算匹配成功。Intent可以不指定category,若Intent中未指定category,系統在調用 startActivity 或者 startActivityForResult 時,會默認爲 Intent 加“android.intent.category.DEFAULT”這個 category 。所以爲了我們的 activity 能夠被隱式調用,就必須在manifest文件中的 Intent-Filter 聲明中帶上“android.intent.category.DEFAULT”。我們可以通過 intent.addCategory方法爲Intent添加category

(3)data的匹配規則
    data 的匹配規則和 action 類似,如果 Intent-Filter中定義了 data,則 Intent 中必須也要定義可匹配的 data。data 的語法如下所示:
<data android:scheme="String"
      android:host="String"
      android:port="String"
      android:path="String"
      android:pathPrefix="String"
      android:pathPattern="String"
      android:mimeType="String"/>

    data 由 mimeType 和 URI 兩部分組成。
    mimeType 指定媒體類型,如 image/jepeg、audio/mpeg4-generic、video/* 等,可以表示圖片、文本、視頻等不同的媒體格式。
    URI 的結構如下:
<scheme>://<host>:<port>/[<path>|<pathPrefix>|<pathPattern>]
   比如下面的兩個URI
content://com.example.project:200/folder/subfolder/etc
http://www.baidu.com:80/search/info
scheme:URI 的模式,比如http、file、content 等,如果URI 中沒有指定 scheme,則整個URI 的其他參數無效,URI 無效
host:URI 的主機名,比如 www.baidu.com ,如果host  未指定,則整個URI 的其他參數無效,URI 無效
port:URI 中的端口號,比如 80,僅當 URI 中指定了 scheme 和 host 參數的時候,port 參數纔有意義
path、pathPrefix、pathPattern:表述路徑信息,其中 path 表示完整的路徑信息,pathPattern 也表示完整的路徑信息,但它裏面可以包含通配符 “*”,“*” 表示0個或多個任意字符,由於正則表達式的規範,如果想標示真實的字符串,“*” 要改寫成“\\*”,“\” 要改寫成“\\\”;pathPrefix 表示路徑的前綴信息。
    Intent的 uri 可通過 setData 方法設置,mimetype 可通過 setType 方法設置。隱式 Intent 也必須指定 data。同 action類似,只要 Intent 的 data 只要與 Intent-Filter中的任一個 data 聲明完全相同,data 方面就匹配成功。
<intent-filter>
    <data android:mimeType="image/*"/>
</intent-filter>
     這種規則指定了 媒體類型爲所有類型的圖片,則 Intent 中的 mimeType 屬性必須爲 “image/*” 才能匹配,需要注意的是若 Intent-Filter的 data 聲明部分未指定 uri,則缺省 uri 爲 content 或 file,Intent 中的 uri 的 scheme 部分需爲 content或file才能匹配;
intent.staDataAndType(Uri.parse("file:abc"),"image/png")
    若要爲 Intent 指定完整的 data,必須用 setDataAndType 方法,不能先調用 setData 再調用 setType,因爲這兩個方法彼此會清楚對方的值,源碼如下:
    setData源碼:
public Intent setData(Uri data) {
    mData = data;
    mType = null;
    return this;
}
   setType源碼:
public Intent setType(String type) {
    mData = null;
    mType = type;
    return this;
}
    從以上代碼可以看到,setData會把mimeType置爲null,setType會把uri置爲null。下面我們來舉例說明一下data的匹配。
    在data 語法中,scheme、host等各個部分無需全部指定。假如我們爲MyActivity的 Intent-Filter 指定了如下data:
<intent-filter>
    <data android:mimeType="vidoe/mpeg" android:scheme="http" android:host="www.xxx.com" />
    <data android:mimeType="text/plain" android:scheme="http" />
</intent-filter>
    那麼我們的Intent想要匹配,mimeType可以爲”text/plain"或“video/mpeg",scheme必須爲”http“,host則沒有限制,因爲第二個data沒有指定host。
intent.staDataAndType(Uri.parse("http:www.xxx.com"),"vidoe/mpeg")
intent.staDataAndType(Uri.parse("http:abc"),"text/plain")
    data 有兩種特殊的寫法,它們的作用是一樣的,如下所示:
<intent-filter>
    <data android:host="www.baidu.com"
          android:scheme="file"/>
</intent-filter>

<intent-filter>
    <data android:scheme="file"/>
    <data android:host="www.baidu.com"/>
</intent-filter>

(4)查詢是否有可接收指定 Intent 的 Activity
    當我們通過影視方式啓動一個 Activity 時,可做一下判斷,看是否有Activity 能夠匹配我們的隱式 Intent,如果不做判斷,有可能出現找不到 Activity 的異常。
    採用 PackageManager 的resolveActivity 或者 Intent 的 resolveActivity 方法會獲得最適合Intent的一個Activity,如果找不到匹配的 Activity 就會返回null , 我們通過判斷返回值就可避免出現找不到 Activity 的異常,PackageManager 還提供了 queryIntentActivities 方法查找所有成功匹配 Intent 的 Activity。
    queryIntentActivities 和 resolveActivity 方法原型:
public abstract List<ResolveInfo> queryIntentActivities(Intent intent,
            @ResolveInfoFlags int flags);

public abstract ResolveInfo resolveActivity(Intent intent, @ResolveInfoFlags int flags);
    上述兩個方法的第一個參數就是Intent,第二個參數我們要使用 MATCH_DEFAULT_ONLY 這個標記位,這個標記位的含義是僅僅匹配那些在 intent-filter 中聲明 <category android:name="android.intent.category.DEFAULT"/> 這個 catefory的Activity。使用的意義在於只要上述兩個方法不返回 null,則 startActivity 一定可以成功。如果不用這個標記位,就可以把 intent-filter 中 category 不含 DEFAULT 的那些Activity 匹配出來,從而導致 startActivity 失敗。因爲不含 DEFAULT 這個 category 的Activity 是無法接收隱式 Intent 的。針對 Service 和BroadcastReceiver,PackageManager 同樣提供了類似的方法去獲取匹配的組件信息。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章