Android IntentFilter匹配規則

顯式調用

Intent intent = new Intent();
intent.setClassName(“lbb.demo.anotest”, “lbb.demo.anotest.TwoActivity”);
startActivity(intent);
打開包名爲”lbb.demo.anotest”的 “lbb.demo.anotest.TwoActivity”方法。。。可能啓動另外一個app

new Intent(this,AnoActivity.class); 打開當前應用的AnoActivity

隱式調用

Action,Catogory匹配

//此時action爲”lbb.demo.anotest.TwoActivity”,同時默認添加DEFAULT的category
Intent intent = new Intent(“lbb.demo.anotest.TwoActivity”);
//intent.addCategory(“android.intent.category.DEFAULT”);
startActivity(intent);
//此時根據AMS規則,是全局查找的。。。並不是只針對於當前應用。。可能啓動另外一個app

        <activity
            android:name=".TwoActivity"
            android:label="@string/title_activity_two"
            android:theme="@style/AppTheme.NoActionBar">
            <intent-filter>
                <action android:name="lbb.demo.anotest.TwoActivity"/>
                <category android:name="android.intent.category.DEFAULT"/>
            </intent-filter>
        </activity>

category android:name=”android.intent.category.DEFAULT”這樣是必不可少的。否則隱式匹配不到該activity,同時注意大小寫匹配

Data匹配

Each element can specify a URI and a data type (MIME media type). There are separate attributes —scheme, host, port, and path — for each part of the URI:
scheme://host:port/path or pathPrefix or pathPattern
For example, in the following URI,
content://com.example.project:200/folder/subfolder/etc
the scheme is “content”, the host is “com.example.project”, the port is “200”, and the path is “folder/subfolder/etc”.

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 中使用又是一次。如:“” 這個字符就應該寫成 “//”,“/” 這個字符就應該寫成 “////”。

setType 調用後設置 mimeType,然後將 data 置爲 null;
setData 調用後設置 data,然後將 mimeType 置爲 null;
setDataAndType 調用後纔會同時設置 data 與 mimeType。
setDataAndType不等同於先調用setData後調用setType,尤其注意

URI的schema是有默認值的,默認值是”content”/”file”

<intent-filter>
    <data android:mimeType="video/mpeg"/>
</intent-filter>

//正確方式
intent.setDataAndType(Uri.parse("file://abc"), "video/mpeg");
intent.setDataAndType(Uri.parse("content://abc"), "video/mpeg");
intent.setType("video/mpeg");

intent.setDataAndType(Uri.parse(“http://abc“), “video/mpeg”);
這樣是匹配不到的,因爲schema部分不匹配默認值是”content”/”file”

PackageManager相關方法

如果有多個action匹配就會出現選擇框。。如果沒有任何一個,就會Force Close,所以可以通過方法檢查是否有符合條件的activity,避免FC
PackageManager方法

    /**
     * Determine the best action to perform for a given Intent.  This is how
     * {@link Intent#resolveActivity} finds an activity if a class has not
     * been explicitly specified.
     *
     * <p><em>Note:</em> if using an implicit Intent (without an explicit ComponentName
     * specified), be sure to consider whether to set the {@link #MATCH_DEFAULT_ONLY}
     * only flag.  You need to do so to resolve the activity in the same way
     * that {@link android.content.Context#startActivity(Intent)} and
     * {@link android.content.Intent#resolveActivity(PackageManager)
     * Intent.resolveActivity(PackageManager)} do.</p>
     *
     * @param intent An intent containing all of the desired specification
     *               (action, data, type, category, and/or component).
     * @param flags Additional option flags.  The most important is
     * {@link #MATCH_DEFAULT_ONLY}, to limit the resolution to only
     * those activities that support the {@link android.content.Intent#CATEGORY_DEFAULT}.
     *
     * @return Returns a ResolveInfo containing the final activity intent that
     *         was determined to be the best action.  Returns null if no
     *         matching activity was found. If multiple matching activities are
     *         found and there is no default set, returns a ResolveInfo
     *         containing something else, such as the activity resolver.
     *
     * @see #MATCH_DEFAULT_ONLY
     * @see #GET_INTENT_FILTERS
     * @see #GET_RESOLVED_FILTER
     */
    public abstract ResolveInfo resolveActivity(Intent intent, int flags);

    /**
     * Retrieve all activities that can be performed for the given intent.
     *
     * @param intent The desired intent as per resolveActivity().
     * @param flags Additional option flags.  The most important is
     * {@link #MATCH_DEFAULT_ONLY}, to limit the resolution to only
     * those activities that support the {@link android.content.Intent#CATEGORY_DEFAULT}.
     *
     * @return A List&lt;ResolveInfo&gt; containing one entry for each matching
     *         Activity. These are ordered from best to worst match -- that
     *         is, the first item in the list is what is returned by
     *         {@link #resolveActivity}.  If there are no matching activities, an empty
     *         list is returned.
     *
     * @see #MATCH_DEFAULT_ONLY
     * @see #GET_INTENT_FILTERS
     * @see #GET_RESOLVED_FILTER
     */
    public abstract List<ResolveInfo> queryIntentActivities(Intent intent,
            int flags);

看兩個方法的註釋

resolveActivity返回最佳匹配,找不到匹配的返回null
queryIntentActivities 返回所有的,找不到匹配的返回null
flags必須是CATEGORY_DEFAULT,增加catogory匹配規則,否則會忽略category匹配,那麼可能會導致startactivity/startservice失敗

最後實現肯定是通過PMS(PackageManagerService)執行對應方法,IBinder通信

綜合前面,AMS,WMS,PMS都介紹過了。

例子

       <activity
            android:name=".TestActivity"
            android:label="@string/title_activity_test"
            android:theme="@style/AppTheme.NoActionBar">
            <intent-filter>
                <action android:name="android.intent.action.TestActivity"/>
                <category android:name="android.intent.category.DEFAULT"/>
                <data
                    android:host="baidu"
                    android:mimeType="image/png"
                    android:scheme="http"/>
            </intent-filter>
        </activity>
    @OnClick(R.id.but)
    void OnClick() {
        Intent intent = new Intent();
        intent.setAction("android.intent.action.TestActivity");
        intent.setDataAndType(Uri.parse("http://baidu:8888/abc/..."), "image/png");
        PackageManager pm = getPackageManager();
        if (pm.resolveActivity(intent, PackageManager.MATCH_DEFAULT_ONLY) != null) {
            startActivity(intent);
        }else{
            Log.d("LiaBin","no match intent");
        }
    }
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章