IntentFilter匹配規則

前言

我們都知道,啓動Activity有兩種方式,即隱式啓動顯式啓動。從優先級來說,顯式啓動要優先於隱式啓動。隱式啓動的優點是使用上的靈活性。因此,掌握隱式啓動中IntentFilter的匹配規則就至關重要了。

對一個Activity而言,可以在AndroidManifest文件中指定多個IntentFilter,Intent只要能夠匹配其中任意一個就算匹配成功。在一個IntentFilter中,可以有多個action、category和data。所有的action組成action類別。同理,所有的category和data分別組成category類別和data類別。Intent需要和action類別、category類別和data類別全部匹配成功,纔算是和這個IntentFilter匹配成功。針對不同的類別,有着不同的匹配規則,具體細節見下文。

action的匹配規則

直觀來說,action是一個字符串。Android系統提供了一些預定義的action,它們都有着自己的含義,我們可以直接使用。當然,我們也可以定義自己的action,以便滿足我們自己的業務需求。在一個IntentFilter中,可以有多個action。Intent只要能和其中任意一個 action匹配就算是匹配成功。否則,匹配失敗。

category的匹配規則

category也是一個字符串,Android系統同樣爲我們提供了一些預定義的category。當然,我們也可以定義自己的category。category的匹配規則和action有所不同。一個IntentFilter中可以有多個category,並不要求Intent全部匹配。但是,要求Intent中添加的任意一個category,都必須已經包含在IntentFilter中了,否則匹配失敗。

需要注意的是,即使不爲Intent添加category,在調用startActivity或者startActivityForResult方法後,Android系統都會爲Intent添加一個預定義的category,即android.intent.category.DEFAULT。因此,我們需要爲Activity的IntentFilter指定這個category,否則會造成匹配失敗。

data的匹配規則

相比action和category,data的匹配規則要稍微複雜一點。首先,要明白data分爲URImimeType兩部分。一個典型的data結構如下所示:

<data
    android:scheme="string"
    android:host="string"
    android:port="string"
    android:path="string"
    android:pathPattern="string"
    android:pathPrefix="string"
    android:mimeType="string">
 </data>

android:mimeType屬性指定了mimeType部分,主要是指定媒體類型。如text/plain、video/*等。URI部分則由剩餘的屬性共同組成。一個URI的結構如下:

scheme://host:port/[path|pathPrefix|pathPattern]

具體的屬性含義如下:

  • scheme:URI的協議名,如http、file、content等,必須指定。
  • host:URI的主機名,如www.coding.com,必須指定。
  • port:URI的端口名,可選。
  • path、pathPrefix和pathPattern:共同組成URI的路徑內容。path和pathPattern都表示完整路徑。不同之處在於pathPattern可以指定通配符*。pathPrefix則表示路徑前綴。

一個IntentFilter可以包含多個data,Intent只要能夠匹配其中任何一個data就算是匹配成功。對於單個data而言,Intent需要匹配所有內容纔算是匹配成功。

需要注意的是,如果一個data沒有指定URI部分,而只是指定了mimeType部分,這個data也是有默認URI的。URI部分會被Android系統指定爲file和content。例如一個data如下:

<data android:mimeType="text/plain"></data>

如果我們要匹配這個data,就需要在Intent中指定URI爲file或者content才行。如下所示:

Intent intent=new Intent();
intent.setDataAndType(Uri.parse("file://"),"text/plain");

需要注意的是,應該使用setDataAndType方法爲Intent設置URI和mimeType。因爲如果單獨使用setDatasetType,它們會相互清除對方設置的值。

一個完整的匹配示例

IntentFilter如下所示:

<intent-filter>
      <action android:name="com.codingending.action.test_1"></action>
      <action android:name="com.codingending.action.test_2"></action>

      <category android:name="com.codingending.category.test_1"></category>
      <category android:name="com.codingending.category.test_2"></category>
      <category android:name="android.intent.category.DEFAULT"></category>

      <data android:mimeType="text/plain"></data>
 </intent-filter>

如果想要匹配上述IntentFilter,可以採取下面的方式:

Intent intent=new Intent();
intent.setAction("com.codingending.action.test_1");
intent.addCategory("com.codingending.category.test_1");
intent.setDataAndType(Uri.parse("file://"),"text/plain");

或者:

Intent intent=new Intent();
intent.setAction("com.codingending.action.test_2");
intent.addCategory("com.codingending.category.test_1");
intent.addCategory("com.codingending.category.test_2");
intent.setDataAndType(Uri.parse("file://"),"text/plain");

特殊的IntentFilter

在Android存在一個特殊的IntentFilter,如下所示:

<intent-filter>
     <action android:name="android.intent.action.MAIN" />
     <category android:name="android.intent.category.LAUNCHER" />
</intent-filter>

這個IntentFilter的作用是標識其所在的Activity是應用的入口Activity,即主Activity。這是應用啓動後呈現給用戶的第一個Activity。

最佳實踐

使用隱式啓動方式最大的缺點是可能匹配失敗造成應用出現ForceClose錯誤,這樣會給用戶不好的使用體驗。因此,在使用隱式啓動方式時,最好先查詢一下是否存在能夠匹配的Activity。只有存在能夠匹配的Activity時,才真正地去啓動它。要達到這一目的,可以使用Intent的resolveActivity方法。或者,也可以使用PackageManagerresolveActivityqueryIntentActivities方法。它們的方法原型如下所示:

Intent:

public ComponentName resolveActivity(PackageManager pm);

packageManager:

public abstract ResolveInfo resolveActivity(Intent intent, int flags);
public abstract List<ResolveInfo> queryIntentActivities(Intent intent,int flags);

resolveActivityqueryIntentActivities的不同之處在於,前者會返回最佳的匹配結果,而後者將返回所有匹配成功的結果。

對於這兩個方法中的flags參數,可以選擇MATCH_DEFAULT_ONLY或者MATCH_ALL,一般選擇前者。如果使用MATCH_DEFAULT_ONLY參數,匹配過程中將會忽略category中不含android.intent.category.DEFAULT的Activity,因爲這些Activity無法被啓動。原因前文已經說過。

通過判斷這些方法的返回值是否爲null,可以知道是否能夠匹配成功。這樣處理後,可以避免應用出現ForceClose錯誤,也優化了用戶體驗。

發佈了49 篇原創文章 · 獲贊 77 · 訪問量 6萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章