Activity的顯示調(diào)用和隱式調(diào)用

我們知道,啟動(dòng)一個(gè)Activity分為兩用,隱式調(diào)用和顯式調(diào)用。原則上一個(gè)Intent不應(yīng)該即是顯式調(diào)用有是隱式調(diào)用,如果二者共存以顯式調(diào)用為主。

顯式調(diào)用

需要明確指定被啟動(dòng)對(duì)象的組件信息,包括包名和類名。一般是在相同的應(yīng)用程序內(nèi)部實(shí)現(xiàn)的。
以兩個(gè)Activity之間的跳轉(zhuǎn)為例:

Intent intent = new Intent(MainActivity.this, TestActivity.class);
startActivity(intent);

隱式調(diào)用

通過Intent Filter來實(shí)現(xiàn)的,它一般用在沒有明確指出目標(biāo)組件名稱的前提下。Android系統(tǒng)會(huì)根據(jù)隱式意圖中設(shè)置的動(dòng)作(action)、類別(category)、數(shù)據(jù)(URI和數(shù)據(jù)類型)找到最合適的組件來處理這個(gè)意圖。一般是用于在不同應(yīng)用程序之間。

下面來詳細(xì)分析各種屬性的匹配規(guī)則

action的匹配規(guī)則

一個(gè)intent filter中可以有多個(gè)action,那么只要intent中的action能和intent filter中的任何一個(gè)action相同集合匹配成功。需要注意的是,intent中沒有指定action,那么匹配失敗。除此之外,action區(qū)分大小寫。

category的匹配規(guī)則

category的匹配規(guī)則和action不同,intent中如果出現(xiàn)了category,不管有幾個(gè),都必須是intent filter中已經(jīng)定義的category,也就是說intent可以沒有category,一旦有,每個(gè)都必須和intent filter中定義的任意一個(gè)category相同。那為什么我們沒在intent filter中加android.intent.category.DEFAULT這個(gè)category會(huì)報(bào)錯(cuò)呢?原因是系統(tǒng)在調(diào)用startActivity或者startActivityForResult的時(shí)候會(huì)默認(rèn)在intent中加上android.intent.category.DEFAULT這個(gè)category。
還是以兩個(gè)Activity之間的跳轉(zhuǎn)為例:

Intent intent = new Intent();
intent.setAction("com.dev.test");
intent.addCategory("com.dev.testcat");
startActivity(intent);

AndroidManifest.xml

<activity android:name=".TestActivity">
            <intent-filter>
                <action android:name="com.dev.test"/>
                <category android:name="com.dev.testcat"/>
                //必須加上,否者報(bào)錯(cuò)
                <category android:name="android.intent.category.DEFAULT"/>
            </intent-filter>
        </activity>

data的匹配規(guī)則

data的匹配規(guī)則和action類似,如果intent filter中定義了data,那么intent中也必須要定義可匹配的data,否者匹配失敗。
首先來了解一下data的結(jié)構(gòu),data由兩部分組成,mimeType和URI。mimeType指媒體類型,比如image/jpeg、text/plaind、video/*等,可以表示圖片、文本、視頻等不同的媒體格式。
了解了data的結(jié)構(gòu),接下來開始介紹data的過濾規(guī)則,下面分情況說明

  • 情況一:data規(guī)則不完整。如下所示
<intent-filter>
      <data android:mimeType="image/*"/>
</intent-filter>

這種規(guī)則指定了媒體類型為所有類型的圖片,那么intent中的mimeType屬性必須為“image/*”才能匹配成功,這種情況雖然沒有指定URI,但intent中的URL部分的schema默認(rèn)值為content和file。也就是說雖然沒有指定URI,但是intent中的URI部分的schema必須為content或者file才能匹配成功,這點(diǎn)尤其需要注意。

  • 情況二:定義了多組data規(guī)則,并且每個(gè)data都定義了完整屬性,既有URI又有mimeType。如下所示
<intent-filter>
    <data android:mimeType="video/mpeg" android:scheme="http" ... />
    <data android:mimeType="audio/mpeg" android:scheme="http" ... />
    ...
</intent-filter>

為了匹配這種intent filter,我們也需要在intent中完整定義其中一組data規(guī)則才能匹配成功。另外,如果要為intent指定完整的data,必須調(diào)用setDataAndType方法,不能先調(diào)用setData再調(diào)用setType,因?yàn)檫@兩個(gè)方法彼此會(huì)清除對(duì)方的值。
最后,但我們通過隱式方式啟動(dòng)一個(gè)Activity時(shí),可以做一下判斷,看是否有Activity能夠匹配我們的intent,以免不必要的奔潰。判斷方法有兩種:一是采用PackageManager的resolveActivity方法,二是采用Intent的resolveActivity方法,如果他們找不到匹配的Activity就會(huì)返回null,根據(jù)其返回值我們就規(guī)避上述問題了。
首先我們來看看Intent的resolveActivity方法源碼

public ComponentName resolveActivity(PackageManager pm) {
        if (mComponent != null) {
            return mComponent;
        }

        ResolveInfo info = pm.resolveActivity(
            this, PackageManager.MATCH_DEFAULT_ONLY);
        if (info != null) {
            return new ComponentName(
                    info.activityInfo.applicationInfo.packageName,
                    info.activityInfo.name);
        }

        return null;
    }

從中我們可以看出其內(nèi)部也是直接調(diào)用了PackageManager的resolveActivity方法來判斷匹配是否成功。
我們?cè)賮砜纯碢ackageManager的resolveActivity方法

public abstract ResolveInfo resolveActivity(Intent intent, int flags);

第一個(gè)參數(shù)很好理解,就是我們要解析的intent,第二個(gè)參數(shù)源碼中使用的是MATCH_DEFAULT_ONLY這個(gè)標(biāo)記位,這個(gè)標(biāo)記位的含義是僅僅匹配那些在intent filter中聲明了<category android:name="android.intent.category.DEFAULT"/>這個(gè)category的Activity。使用它的意義在于只要此方法不返回null,那么startActivity一定可以成功。最后是示例:

Intent intent = new Intent();
intent.setAction("com.dev.test");
intent.setType("image/*");
ComponentName componentName = intent.resolveActivity(getPackageManager());
if (componentName == null) {
    //如果為null,表示匹配失敗
    Toast.makeText(MainActivity.this, "匹配失敗", Toast.LENGTH_SHORT).show();
} else {
    //如果不為null,啟動(dòng)Activity
    startActivity(intent);
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容