4.Intent-filter的匹配規則

 啓動Activity的方式有兩種,一種是顯式調用,一種是隱式調用。顯式調用就是明確指定了啓動對象的組件信息,包括了包名和類名。而隱式調用不需要明確指定組件的信息。顯示調用很簡單,比如我們常用的
            Intent intent = new Intent( mContext , XXActivity.class);    
        或者是使用:
            ComponentName componentName = new ComponentName( "com.xx.xx","com.xx.xx.XXActivity");
            Intent intent = new Intent();
            intent.setComponent( componentName);
            startActivity( intent );
    這些都是使用顯式調用。而隱式調用就比較複雜了,隱式調用要求Intent能夠匹配目標組件(不一定是Activity)的IntentFilter中所設置的過濾信息,如果不匹配將無法啓動目標Activity。
    IntentFilter中的過濾信息有action、category、data。
    爲了匹配過濾列表,需要同時匹配過濾列表中的action、category、data信息,否則匹配失敗。一個過濾列表中的action、category和data可以有多個。所有的action、category、data分別構成不同的類表,同一個類別的信息共同約束當前類別的匹配過程,只有一個Intent同時匹配了action類別,category類別,data類表纔算完全匹配,只有完全匹配才能成功啓動目標Activity,另外一點,一個Activity中可以有多個intent-filter,一個Intent只要能夠匹配任何一組intent-filter就可以成功啓動對應的Activity。
  
    1.action的匹配規則
    action是一個字符串,系統已經預定義了一些action(非常多最最常見的就是:android.intent.action.MAIN),同時我們也可以在應用中定義自己的action。比如com.mapbar.android.OUT_CALL_NAVI .action的匹配規則是Intent 中的action必須要和intentFilter中的action匹配,這裏的匹配是指字符串值一模一樣。一個intentFilter可以有多個action,那麼只要Intent中的action能夠和過濾規則中的任何一個action相同就可以匹配成功。另外要注意了,action是必須要設置的,如果沒有設置action那麼就會匹配失敗。
    故:action的匹配,要求Intent中的action存在並且必須和IntentFilter中的其中一個action相同,action匹配規則和category不同。此外,它是區分大小寫的。

    2.category的匹配規則
    這裏先介紹category的意義,category屬性用於指定當前動作(Action)被執行的環境,一般是理解爲對Action的補充,我認爲,action其實也可以做到這個,只要你定義的action夠多,但是,這樣子做的話,那就不符合面向對象設計的思想,至少,action沒有複用,而且看起來結構性也很差。個人是這樣理解的。
    系統預定義了一些category,同時我們也可以自定義一些category.category的匹配規則和action不同,它要求Intent中如果含有category,那麼所有的category都必須和過濾規則中的其中一個category相同,換句話說,如果在Intent中出現了category那麼,就要求這些category每一個的內容都必須要和IntentFilter中的某一個完全匹配,否則就會匹配失敗。而如果沒有添加category就默認匹配成功,因爲在Actity當中有一個默認的category“android.intent.category.DEFAULT”這個category。而startActivity和startActivityForResult默認會添加這個category。如果想要讓Activity能夠接收隱式調用,那麼就要在Intent-filter的category加上“android.intent.category.DEFAULT",例外情況是:android.intent.category.MAIN和android.intent.category.LAUNCHER的filter中沒有必要加入android.intent.category.DEFAULT,當然加入也沒有問題.
    3.data的匹配規則
    data的匹配規則和action類似,如果過濾規則中定義了data,那麼Intent中必須也要定義匹配的data,在介紹data匹配規則之前,我們先了解一下data的結構。因爲data稍微有些複雜。
    
    <data   android:scheme="string"
                android:host="string"
                android:port="string"
                android:path="string"
                android:pathPattern="string"
                android:pathPrefix="string"
                android:mimeType="string"/>
    
    data由2個模塊組成:
  • mimeType:媒體類型,比如image/jpeg、audio/mpeg4-generic 和video/*等,可以表示圖片、文本、視頻等不同的媒體格式。
  • URI:URI中包含的數據比較多,URI結構如下:
        <scheme>://<host>:<port>/[<path>|<pathPrefix>|<pathPattern>]
    上面的URI是很常見的,不過在這邊還是都介紹下
  • Scheme:URI的模式,比如http、file、content等,如果沒有制定scheme,那麼URI整個都是無效的。
  • Host:主機名,比如www.baidu.com,如果host未指定,那麼整個URI中的其他參數無效,這也意味着URI是無效的。
  • Port:URI的端口號:比如80.僅當URI中指定了scheme和host參數的時候port參數纔是有意義的。
    
    path、pathPattern、pathePrefix:這三個參數表述路徑信息,其中path表示完整的路徑信息:pathPattern也表示完整的路徑信息,但是它裏面可以包含通配符"*","*"表示0個或者多個任意字符,需要注意的是,由於正則表達式的規範,如果想要表示真實的字符串,那麼"*"要寫成"\\*","\"要寫成"\\\\"(思考一下爲什麼是四個),pathPrefix表示路徑的前綴信息。  
    介紹完data的數據格式後,我們要說一下data的匹配規則了,data匹配規則和Action相似,要求Intent中必須有data數據,並且和IntentFilter其中一個data完全匹配。這裏的完全匹配是指過濾規則中出現的data部分也出現在Intent的data中。
    比如如下的過濾規則
    <intent-filter>
        <data android:mimeType="image/*" />
        …………
    </intent-filter>

    匹配時可以寫成如下:
    intent.setDataAndType(Uri.parse("file://abc"),"image/png");

    另外,要指定完整的data 必須要調用setDataAndType方法,不可以先setData再setType,因爲兩者會清楚對方的值。

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

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

上面這兩個寫法效果是一樣的。
考慮一下這個情形:    
    
<intent-filter>
        <data android:scheme="file" />
        <data android:host="www.qq.com"/>
        <data android:scheme="http"/>
    </intent-filter>
這個情況又是如何呢?

   Intent-filter的匹配規則對於Service和BroadcastReceiver也是同樣的道理,不過系統對於Service的建議是儘量使用顯式調用來啓動服務。

    當我們是用隱式調用來啓動一個Activity的時候,我們可以做一下判斷,看看是否有Activity能夠匹配我們的隱式Intent,如果不做判斷就有可能出現ActivityNotFoundException.

    判斷方法有2種:
  • 採用PackManager的resolveActivity方法
  • 採用Intent的resolveActivity方法。
    上述方法找不到匹配的Activity就會返回null.通過判斷返回值就可以規避上面的那個異常。此外,PackageManager還提供了queryIntentActivities方法,這個方法和resolveActivity方法不同的是,它不是返回最佳匹配的Activity信息,而是返回所有成功匹配的Activity信息。我們看一下queryIntentActivities和resolveActivity的方法原型:
     public abstract List<ResolveInfo> queryIntentActivities( Intent intent , int flags);
    public abstract ResolveInfo resolveActivity(Intent intent ,int flags);

上面方法的第一個參數很好理解,關鍵在於第二個參數。我們要使用MATCH_DEFAULT_ONLY 這個標記位,這個標記位含義是隻匹配那些聲明瞭<category android:name="android.intent.category.DEFAULT"/>這個category的Activity。使用這個標記位的意義在於,只要上上述兩個不返回null,那麼startActivity一定可以成功。如果不用這個標記位,就可以把不含Default的那些Activity匹配出來,導致失敗,因爲不含有DEFAULT這個category的activity是無法接收隱式Intent的.例外的情況是這一類的action和category:
    <action android:name="android.intent.action.MAIN">
    <category android:name="android.intent.category.LAUNCHER"/>
這兩者是用來表明這是一個入口Activity,並且會出現在系統應用列表當中,少了其中任何一個都沒有實際的意義,也無法出現在系統的應用列表當中。另外,對於service和broadcastReceiver、PackManager同樣提供了類似的方法去獲取成功匹配的組件信息。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章