Intent 和 IntentFilter

Intent 翻譯為“意圖”,其實是一個消息傳遞對象,Intent可以通過多種方式促進組件之間的通信,但其基本用途主要有以下三種:

(1)啟動Activity

(2)啟動Service

(3)傳遞廣播

廣播是任何應(yīng)用均可接收的消息。系統(tǒng)將針對系統(tǒng)事件(例如:系統(tǒng)啟動或設(shè)備開始充電時)傳遞各種廣播。通過將 Intent 傳遞給 sendBroadcast()、sendOrderedBroadcast()sendStickyBroadcast(),可以將廣播傳遞給其他應(yīng)用。

Intent類型

Intent分兩種類型:

(1)顯式Intent:按名稱(完全限定類名)指定要啟動的組件。

(2)隱式Intent:不會指定特定的組件,而是聲明要執(zhí)行的常規(guī)操作,從而允許其他應(yīng)用中的組件來處理它。 例如,如需在地圖上向用戶顯示位置,則可以使用隱式 Intent,請求另一具有此功能的應(yīng)用在地圖上顯示指定的位置。

創(chuàng)建顯式Intent啟動Activity或其他組件時,系統(tǒng)將立即啟動Intent對象所指定的組件。

創(chuàng)建隱式Intent時,Android系統(tǒng)通過將Intent的內(nèi)容與設(shè)備上的其他應(yīng)用的manifest文件中聲明的Intent過濾器比較從而找到要啟動的相應(yīng)組件。 如果 Intent 與 Intent 過濾器匹配,則系統(tǒng)將啟動該組件,并向其傳遞 Intent對象。 如果多個 Intent 過濾器兼容,則系統(tǒng)會顯示一個對話框,支持用戶選取要使用的應(yīng)用。

通過隱式Intent啟動其他組件的一個過程示例:


image.png

Intent 過濾器是應(yīng)用清單文件中的一個表達式,它指定該組件要接收的 Intent 類型。 例如,通過為 Activity 聲明 Intent 過濾器,您可以使其他應(yīng)用能夠直接使用某一特定類型的 Intent 啟動 Activity。同樣,如果您沒有為 Activity 聲明任何 Intent 過濾器,則 Activity 只能通過顯式 Intent 啟動。

注意:為了確保應(yīng)用的安全性,啟動 Service 時,請始終使用顯式 Intent,且不要為服務(wù)聲明 Intent 過濾器。使用隱式 Intent 啟動服務(wù)存在安全隱患,因為您無法確定哪些服務(wù)將響應(yīng) Intent,且用戶無法看到哪些服務(wù)已啟動。從 Android 5.0(API 級別 21)開始,如果使用隱式 Intent 調(diào)用 bindService(),系統(tǒng)會引發(fā)異常。

構(gòu)建Intent

Intent 對象攜帶了 Android 系統(tǒng)用來確定要啟動哪個組件的信息(例如,準確的組件名稱或應(yīng)當接收該 Intent 的組件類別),以及收件人組件為了正確執(zhí)行操作而使用的信息(例如,要采取的操作以及要處理的數(shù)據(jù))。

Intent 中包含的主要信息如下:

(1)組件名稱(ComponentName)

要啟動的組件名稱。

這是可選項,但也是構(gòu)建顯式 Intent 的一項重要信息,這意味著 Intent 應(yīng)當僅傳遞給由組件名稱定義的應(yīng)用組件。 如果沒有組件名稱,則 Intent 是隱式的,且系統(tǒng)將根據(jù)其他 Intent 信息(例如,以下所述的action、data和category)決定哪個組件應(yīng)當接收 Intent。 因此,如需在應(yīng)用中啟動特定的組件,則應(yīng)指定該組件的名稱。

Intent 的這一字段是一個 ComponentName 對象,您可以使用目標組件的完全限定類名指定此對象,其中包括應(yīng)用的軟件包名稱。 例如, com.example.ExampleActivity。您可以使用 setComponent()、setClass()、setClassName() 或 Intent 構(gòu)造函數(shù)設(shè)置組件名稱。

(2)Action

指定要執(zhí)行的通用操作(例如,“查看”或“選取”)的字符串。

對于廣播 Intent,這是指已發(fā)生且正在報告的action。action在很大程度上決定了其余 Intent 的構(gòu)成,特別是data和 extra 中包含的內(nèi)容。

我們可以指定自己的action,供 Intent 在應(yīng)用內(nèi)使用(或者供其他應(yīng)用在我們的應(yīng)用中調(diào)用組件)。但是,我們通常應(yīng)該使用由 Intent 類或其他框架類定義的action常量。以下是一些用于啟動 Activity 的常見action:

  • ACTION_VIEW
    如果我們擁有一些某項 Activity 可向用戶顯示的信息(例如,要使用圖庫應(yīng)用查看的照片;或者要使用地圖應(yīng)用查看的地址),請使用 Intent 將此action與 startActivity() 結(jié)合使用。

  • ACTION_SEND
    這也稱為“共享”Intent。如果您擁有一些用戶可通過其他應(yīng)用(例如,電子郵件應(yīng)用或社交共享應(yīng)用)共享的數(shù)據(jù),則應(yīng)使用 Intent 將此action與 startActivity() 結(jié)合使用。

有關(guān)更多定義通用action的常量,請參閱 Intent 類參考文檔。 其他操作在 Android 框架中的其他位置定義。例如,對于在系統(tǒng)的設(shè)置應(yīng)用中打開特定屏幕的操作,將在 Settings 中定義。

您可以使用 setAction()Intent 構(gòu)造函數(shù)為 Intent 指定action。

如果定義自己的action,請確保將應(yīng)用的軟件包名稱作為前綴。 例如:

static final String ACTION_TIMETRAVEL = "com.example.action.TIMETRAVEL";

(3)Data

引用待操作數(shù)據(jù)和/或該數(shù)據(jù) MIME 類型的 URI(Uri 對象)。提供的數(shù)據(jù)類型通常由 Intent 的action決定。例如,如果action是 ACTION_EDIT,則數(shù)據(jù)應(yīng)包含待編輯文檔的 URI。

創(chuàng)建Intent時,除了制定URI以外,指定數(shù)據(jù)類型(MIME類型)也很重要。例如,能夠顯示圖像的 Activity 可能無法播放音頻文件,即便 URI 格式十分類似時也是如此。因此,指定數(shù)據(jù)的MIME類型有助于Android系統(tǒng)找到接收Intent的最佳組件。但有時,MIME 類型可以從 URI 中推斷得出,特別當數(shù)據(jù)是 content: URI 時尤其如此。這表明數(shù)據(jù)位于設(shè)備中,且由 ContentProvider 控制,這使得數(shù)據(jù) MIME 類型對系統(tǒng)可見。

若要僅設(shè)置數(shù)據(jù)URI,可以調(diào)用setData()方法,僅設(shè)置MIME類型,可以調(diào)用setType()方法,若要同時設(shè)置URI和MIME類型,可以調(diào)用setDataAndType()方法。

注意:若要同時設(shè)置 URI 和 MIME 類型,請勿調(diào)用 setData()setType(),因為它們會互相抵消彼此的值。請始終使用setDataAndType() 同時設(shè)置 URI 和 MIME 類型。

(4)Category

一個包含應(yīng)處理 Intent 組件類型的附加信息的字符串。 您可以將任意數(shù)量的category描述放入一個 Intent 中,但大多數(shù) Intent 均不需要category。 以下是一些常見category:

  • CATEGORY_BROWSABLE
    目標 Activity 允許本身通過網(wǎng)絡(luò)瀏覽器啟動,以顯示鏈接引用的數(shù)據(jù),如圖像或電子郵件。

  • CATEGORY_LAUNCHER
    該 Activity 是任務(wù)的初始 Activity,在系統(tǒng)的應(yīng)用啟動器中列出。

有關(guān)category的完整列表,可以查看 Intent 類描述。代碼中可以使用 addCategory() 指定類別。

以上列出的這些屬性(組件名稱、操作、數(shù)據(jù)和類別)表示 Intent 的既定特征。 通過讀取這些屬性,Android 系統(tǒng)能夠解析應(yīng)當啟動哪個應(yīng)用組件。但是,Intent 也有可能會一些攜帶不影響其如何解析為應(yīng)用組件的信息。

(5)Extra

攜帶完成請求操作所需的附加信息的鍵值對。正如某些操作使用特定類型的數(shù)據(jù) URI 一樣,有些操作也使用特定的 extra。

我們可以使用各種 putExtra() 方法添加 extra 數(shù)據(jù),每種方法均接受兩個參數(shù):key和value。還可以創(chuàng)建一個包含所有 extra 數(shù)據(jù)的 Bundle 對象,然后使用 putExtras()Bundle 插入 Intent 中。

例如,使用 ACTION_SEND 創(chuàng)建用于發(fā)送電子郵件的 Intent 時,可以使用 EXTRA_EMAIL 鍵指定“目標”收件人,并使用 EXTRA_SUBJECT 鍵指定“主題”。

Intent 類將為標準化的數(shù)據(jù)類型指定多個 EXTRA_* 常量。如需聲明自己的 extra 鍵(對于應(yīng)用接收的 Intent),請確保將應(yīng)用的軟件包名稱作為前綴。 例如:

static final String EXTRA_GIGAWATTS = "com.example.EXTRA_GIGAWATTS";

(6)Flag

在 Intent 類中定義的、充當 Intent 元數(shù)據(jù)的標志。 flag可以指示 Android 系統(tǒng)如何啟動 Activity(例如,Activity 應(yīng)屬于哪個任務(wù),Activity的啟動模式),以及啟動之后如何處理(例如,它是否屬于最近的 Activity 列表)。如需了解詳細信息,請參閱 setFlags() 方法。

隱式Intent示例:

隱式 Intent 指定能夠在可以執(zhí)行相應(yīng)操作的設(shè)備上調(diào)用任何應(yīng)用的操作。 如果您的應(yīng)用無法執(zhí)行該操作而其他應(yīng)用可以,且您希望用戶選取要使用的應(yīng)用,則使用隱式 Intent 非常有用。

例如,如果我們希望用戶與他人共享一個內(nèi)容,可以使用 ACTION_SEND 操作創(chuàng)建 Intent,并添加指定共享內(nèi)容的 extra。 使用該 Intent 調(diào)用 startActivity() 時,用戶可以選取共享內(nèi)容所使用的應(yīng)用。

注意:用戶可能沒有任何應(yīng)用處理程序發(fā)送到 startActivity() 的隱式 Intent。如果出現(xiàn)這種情況,則調(diào)用將會失敗,且應(yīng)用會崩潰。要驗證 Activity 是否會接收 Intent,請對 Intent 對象調(diào)用 resolveActivity()。如果結(jié)果為非空,則至少有一個應(yīng)用能夠處理該 Intent,且可以安全調(diào)用 startActivity()。 如果結(jié)果為空,則不應(yīng)使用該 Intent。如有可能,應(yīng)該停用發(fā)出該 Intent 的功能。

// Create the text message with a string
Intent sendIntent = new Intent();
sendIntent.setAction(Intent.ACTION_SEND);
sendIntent.putExtra(Intent.EXTRA_TEXT, textMessage);
sendIntent.setType("text/plain");

// Verify that the intent will resolve to an activity
if (sendIntent.resolveActivity(getPackageManager()) != null) {
    startActivity(sendIntent);
}

PS:在這種情況下,系統(tǒng)并沒有使用URI,但已聲明Intent的數(shù)據(jù)類型,用于指定extra攜帶的內(nèi)容。

調(diào)用 startActivity() 時,系統(tǒng)將檢查已安裝的所有應(yīng)用,確定哪些應(yīng)用能夠處理這種 Intent(即:含 ACTION_SEND 操作并攜帶“text/plain”數(shù)據(jù)的 Intent )。 如果只有一個應(yīng)用能夠處理,則該應(yīng)用將立即打開并為其提供 Intent。 如果多個 Activity 接受 Intent,則系統(tǒng)將顯示一個對話框,使用戶能夠選取要使用的應(yīng)用。

強制使用應(yīng)用選擇器:

如果有多個應(yīng)用響應(yīng)隱式 Intent,則用戶可以選擇要使用的應(yīng)用,并將其設(shè)置為該操作的默認選項。 如果用戶可能希望今后一直使用相同的應(yīng)用執(zhí)行某項操作(例如,打開網(wǎng)頁時,用戶往往傾向于僅使用一種網(wǎng)絡(luò)瀏覽器),則這一點十分有用。但是,如果多個應(yīng)用可以響應(yīng) Intent,且用戶可能希望每次使用不同的應(yīng)用,則應(yīng)采用顯式方式顯示選擇器對話框。 選擇器對話框每次都會要求用戶選擇用于操作的應(yīng)用(用戶無法為該操作選擇默認應(yīng)用)。 例如,當應(yīng)用使用 ACTION_SEND 操作執(zhí)行“共享”時,用戶根據(jù)目前的狀況可能需要使用另一不同的應(yīng)用,因此應(yīng)當始終使用選擇器對話框。

要顯示選擇器,可以使用createChooser() 創(chuàng)建 Intent,并將其傳遞給 startActivity()。例如

Intent sendIntent = new Intent(Intent.ACTION_SEND);
...

// Always use string resources for UI text.
// This says something like "Share this photo with"
String title = getResources().getString(R.string.chooser_title);
// Create intent to show the chooser dialog
Intent chooser = Intent.createChooser(sendIntent, title);

// Verify the original intent will resolve to at least one activity
if (sendIntent.resolveActivity(getPackageManager()) != null) {
    startActivity(chooser);
}

這將顯示一個對話框,其中有響應(yīng)傳遞給createChooser方法的Intent應(yīng)用列表,并且將提供的文本作為對話框的標題。

接收隱式Intent:

上面介紹了創(chuàng)建一個隱式Intent,下面說一下如何接收一個隱式的Intent。要想公布應(yīng)用可以接收哪些Intent,需要在manifest文件中使用 <intent-filter> 元素為每個應(yīng)用組件聲明一個或多個 Intent 過濾器。每個Intent過濾器均根據(jù)action、data、category指定自身接收的Intent類型。僅當隱式Intent可以通過Intent過濾器之一傳遞時,系統(tǒng)才會將該Intent傳遞給該組件。

注:顯式 Intent 始終會傳遞給其目標,無論組件聲明的 Intent 過濾器如何均是如此。

應(yīng)用組件應(yīng)當為自身可執(zhí)行的每個獨特作業(yè)聲明單獨的過濾器。例如,圖像庫應(yīng)用中的一個 Activity 可能會有兩個過濾器,分別用于查看圖像和編輯圖像。 當 Activity 啟動時,它將檢查 Intent 并根據(jù) Intent 中的信息決定具體的行為(例如,是否顯示編輯器控件)。

每個 Intent 過濾器均由應(yīng)用清單文件中的 <intent-filter> 元素定義,并嵌套在相應(yīng)的應(yīng)用組件(例如,<activity> 元素)中。 在 <intent-filter> 內(nèi)部,您可以使用以下三個元素中的一個或多個指定要接受的 Intent 類型:

<action>

在 name 屬性中,聲明接受的 Intent 操作。該值必須是操作的文本字符串值,而不是類常量。

<data>

使用一個或多個指定數(shù)據(jù) URI 各個方面(scheme、host、port、path 等)和 MIME 類型的屬性,聲明接受的數(shù)據(jù)類型。

<category>

在 name 屬性中,聲明接受的 Intent 類別。該值必須是操作的文本字符串值,而不是類常量。

注:為了接收隱式 Intent,必須將 CATEGORY_DEFAULT 類別包括在 Intent 過濾器中。 方法 startActivity()startActivityForResult() 將按照已申明 CATEGORY_DEFAULT 類別的方式處理所有 Intent。 如果未在 Intent 過濾器中聲明此類別,則隱式 Intent 不會解析到該 Activity。示例:

<activity android:name="ShareActivity">
    <intent-filter>
        <action android:name="android.intent.action.SEND"/>
        <category android:name="android.intent.category.DEFAULT"/>
        <data android:mimeType="text/plain"/>
    </intent-filter>
</activity>

您可以創(chuàng)建一個包括多個 <action><data><category> 實例的過濾器。創(chuàng)建時,僅需確定組件能夠處理這些過濾器元素的任何及所有組合即可。

如需僅以操作、數(shù)據(jù)和類別類型的特定組合來處理多種 Intent,則需創(chuàng)建多個 Intent 過濾器。

限制對組件的訪問:使用 Intent 過濾器時,無法安全地防止其他應(yīng)用啟動組件。 盡管 Intent 過濾器將組件限制為僅響應(yīng)特定類型的隱式 Intent,但如果開發(fā)者確定您的組件名稱,則其他應(yīng)用有可能通過使用顯式 Intent 啟動您的應(yīng)用組件。如果必須確保只有您自己的應(yīng)用才能啟動您的某一組件,請針對該組件將 exported 屬性設(shè)置為 "false"。

系統(tǒng)通過將 Intent 與所有這三個元素進行比較,根據(jù)過濾器測試隱式 Intent。 隱式 Intent 若要傳遞給組件,必須通過所有這三項測試。如果 Intent 甚至無法匹配其中任何一項測試,則 Android 系統(tǒng)不會將其傳遞給組件。 但是,由于一個組件可能有多個 Intent 過濾器,因此未能通過某一組件過濾器的 Intent 可能會通過另一過濾器。

注意:為了避免無意中運行不同應(yīng)用的 Service,請始終使用顯式 Intent 啟動服務(wù),且不必為該服務(wù)聲明 Intent 過濾器。

注:對于所有 Activity,您必須在清單文件中聲明 Intent 過濾器。但是,廣播接收器的過濾器可以通過調(diào)用 registerReceiver() 動態(tài)注冊。 之后可以使用 unregisterReceiver() 注銷該接收器。這樣一來,應(yīng)用便可僅在應(yīng)用運行時的某一指定時間段內(nèi)偵聽特定的廣播。

<activity android:name="MainActivity">
    <!-- This activity is the main entry, should appear in app launcher -->
    <intent-filter>
        <action android:name="android.intent.action.MAIN" />
        <category android:name="android.intent.category.LAUNCHER" />
    </intent-filter>
</activity>

<activity android:name="ShareActivity">
    <!-- This activity handles "SEND" actions with text data -->
    <intent-filter>
        <action android:name="android.intent.action.SEND"/>
        <category android:name="android.intent.category.DEFAULT"/>
        <data android:mimeType="text/plain"/>
    </intent-filter>
    <!-- This activity also handles "SEND" and "SEND_MULTIPLE" with media data -->
    <intent-filter>
        <action android:name="android.intent.action.SEND"/>
        <action android:name="android.intent.action.SEND_MULTIPLE"/>
        <category android:name="android.intent.category.DEFAULT"/>
        <data android:mimeType="application/vnd.google.panorama360+jpg"/>
        <data android:mimeType="image/*"/>
        <data android:mimeType="video/*"/>
    </intent-filter>
</activity>

MainActivity是應(yīng)用的主要入口點,當用戶最初在桌面點擊圖標時該Activity將被啟動。

  • ACTION_MAIN 操作指示這是主要入口點,且不要求輸入任何 Intent 數(shù)據(jù)。

  • CATEGORY_LAUNCHER 類別指示此 Activity 的圖標應(yīng)放入系統(tǒng)的應(yīng)用啟動器。 如果 <activity> 元素未使用 icon 指定圖標,則系統(tǒng)將使用 <application> 元素中的圖標。

這兩個元素必須配對使用,Activity 才會顯示在應(yīng)用啟動器Launcher中。

第二個 ShareActivity 旨在便于共享文本和媒體內(nèi)容。 盡管用戶可以通過從 MainActivity 導航進入此 Activity,但也可以從發(fā)出隱式 Intent(與兩個 Intent 過濾器之一匹配)的另一應(yīng)用中直接進入 ShareActivity。

注:MIME 類型 application/vnd.google.panorama360+jpg 是一個指定全景照片的特殊數(shù)據(jù)類型,可以使用 Google panorama API 對其進行處理。

使用PendingIntent:

PendingIntent 對象是 Intent 對象的包裝器。PendingIntent 的主要目的是授權(quán)外部應(yīng)用使用包含的 Intent,就像是它從應(yīng)用本身的進程中執(zhí)行的一樣。

PendingIntent 的主要用途包括:

  • 聲明用戶使用應(yīng)用的通知執(zhí)行操作時所要執(zhí)行的 Intent(Android 系統(tǒng)的 NotificationManager 執(zhí)行 Intent)

  • 聲明用戶使用應(yīng)用的 應(yīng)用小部件執(zhí)行操作時要執(zhí)行的 Intent(主屏幕應(yīng)用執(zhí)行 Intent)

  • 聲明未來某一特定時間要執(zhí)行的 Intent(Android 系統(tǒng)的 AlarmManager 執(zhí)行 Intent)

由于每個 Intent 對象均設(shè)計為由特定類型的應(yīng)用組件(Activity、ServiceBroadcastReceiver)進行處理,因此還必須基于相同的考慮因素創(chuàng)建 PendingIntent。使用PendingIntent 時,應(yīng)用不會使用調(diào)用(如 startActivity())執(zhí)行該 Intent。相反,通過調(diào)用相應(yīng)的創(chuàng)建器方法創(chuàng)建PendingIntent 時,我們必須聲明所需的組件類型:

除非應(yīng)用正在從其他應(yīng)用中接收待定 Intent,否則上述用于創(chuàng)建 PendingIntent 的方法可能是我們所需的唯一 PendingIntent 方法。

每種方法均會提取當前的應(yīng)用 Context、要包裝的 Intent 以及一個或多個指定應(yīng)如何使用該 Intent 的標志(例如,是否可以多次使用該 Intent)。

Intent的匹配:

當系統(tǒng)收到隱式 Intent 以啟動 Activity 時,它根據(jù)以下三個方面將該 Intent 與 Intent 過濾器進行匹配,搜索該 Intent 的最佳 Activity:

(1)Action匹配

要指定接受的 Intent 操作,Intent 過濾器既可以不聲明任何 <action> 元素,也可以聲明多個此類元素。

要通過此過濾器,我們在 Intent 中指定的action必須與過濾器中列出的某一action匹配。

如果該過濾器未列出任何action,則 Intent 沒有任何匹配項,因此所有 Intent 均無法通過測試。 但是,如果 Intent 未指定action,則會通過測試(只要過濾器至少包含一個action)。

(2)Category匹配

要指定接受的 Intent 類別, Intent 過濾器既可以不聲明任何 <category> 元素,也可以聲明多個此類元素。

若要使 Intent 通過category匹配,則 Intent 中的每個category 均必須與過濾器中的category匹配。反之則未必然,Intent 過濾器聲明的類別可以超出 Intent 中指定的數(shù)量,且 Intent 仍會通過測試。 因此,不含category 的 Intent 應(yīng)當始終會通過此測試,無論過濾器中聲明何種category均是如此。

:Android 會自動將 CATEGORY_DEFAULT 類別應(yīng)用于傳遞給 startActivity()startActivityForResult() 的所有隱式 Intent。因此,如需 Activity 接收隱式 Intent,則必須將 "android.intent.category.DEFAULT" 的類別包括在其 Intent 過濾器中(如上文的 <intent-filter> 示例所示)。

(3)Data匹配

要指定接受的 Intent 數(shù)據(jù), Intent 過濾器既可以不聲明任何 <data> 元素,也可以聲明多個此類元素。

每個 <data> 元素均可指定 URI 結(jié)構(gòu)和數(shù)據(jù)類型(MIME 媒體類型)。 URI 的每個部分均包含單獨的 scheme、host、port 和 path 屬性:

<scheme>://<host>:<port>/<path>

例如:

    content://com.example.project:200/folder/subfolder/etc

<data> 元素中,上述每個屬性均為可選,但存在線性依賴關(guān)系:

  • 如果未指定scheme,則會忽略host。

  • 如果未指定host,則會忽略port。

  • 如果未指定scheme和host,則會忽略path。

將 Intent 中的 URI 與過濾器中的 URI 規(guī)范進行比較時,它僅與過濾器中包含的部分 URI 進行比較。 例如:

  • 如果過濾器僅指定scheme,則具有該scheme的所有 URI 均與該過濾器匹配。

  • 如果過濾器指定scheme和權(quán)限,但未指定path,則具有相同scheme和權(quán)限的所有 URI 都會通過過濾器,無論其path如何均是如此。

  • 如果過濾器指定scheme、權(quán)限和path,則僅具有相同scheme、權(quán)限和path的 URI 才會通過過濾器。

注:路徑規(guī)范可以包含星號通配符 (*),因此僅需部分匹配路徑名即可。

data匹配會將 Intent 中的 URI 和 MIME 類型與過濾器中指定的 URI 和 MIME 類型進行比較。 規(guī)則如下:

  • 僅當過濾器未指定任何 URI 或 MIME 類型時,不含 URI 和 MIME 類型的 Intent 才會通過測試。

  • 對于包含 URI 但不含 MIME 類型(既未顯式聲明,也無法通過 URI 推斷得出)的 Intent,僅當其 URI 與過濾器的 URI 格式匹配、且過濾器同樣未指定 MIME 類型時,才會通過測試。

  • 僅當過濾器列出相同的 MIME 類型且未指定 URI 格式時,包含 MIME 類型、但不含 URI 的 Intent 才會通過測試。

  • 僅當 MIME 類型與過濾器中列出的類型匹配時,同時包含 URI 類型和 MIME 類型(通過顯式聲明,或可以通過 URI 推斷得出)的 Intent 才會通過測試的 MIME 類型部分。 如果 Intent 的 URI 與過濾器中的 URI 匹配,或者如果 Intent 具有 content: 或 file: URI 且過濾器未指定 URI,則 Intent 會通過測試的 URI 部分。 換言之,如果過濾器只是列出 MIME 類型,則假定組件支持 content: 和 file: 數(shù)據(jù)。

最后一條規(guī)則,反映了期望組件能夠從文件中或ContentProvider獲得本地數(shù)據(jù)。因此,其過濾器可以僅列出數(shù)據(jù)類型,而不必顯式命名 content: 和 file: 架構(gòu)。

例如,下面代碼中的 <data> 元素向 Android 指出,組件可從內(nèi)容提供商處獲得并顯示圖像數(shù)據(jù):

<intent-filter>
    <data android:mimeType="image/*" />
    ...
</intent-filter>

由于大部分可用數(shù)據(jù)均由內(nèi)容提供商分發(fā),因此指定數(shù)據(jù)類型(而非 URI)的過濾器也許最為常見。

另一常見的配置是具有架構(gòu)和數(shù)據(jù)類型的過濾器。例如,下文中的 <data> 元素向 Android 指出,組件可從網(wǎng)絡(luò)中檢索視頻數(shù)據(jù)以執(zhí)行操作:

<intent-filter>
    <data android:scheme="http" android:type="video/*" />
    ...
</intent-filter>

通過 Intent 過濾器匹配 Intent,這不僅有助于發(fā)現(xiàn)要激活的目標組件,還有助于發(fā)現(xiàn)設(shè)備上組件集的相關(guān)信息。 例如,主頁應(yīng)用通過使用指定 ACTION_MAIN 操作和 CATEGORY_LAUNCHER 類別的 Intent 過濾器查找所有 Activity,以此填充應(yīng)用啟動器。

我們的應(yīng)用可以采用類似的方式使用 Intent 匹配。PackageManager 提供了一整套 query...() 方法來返回所有能夠接受特定 Intent 的組件。此外,它還提供了一系列類似的 resolve...() 方法來確定響應(yīng) Intent 的最佳組件。 例如,queryIntentActivities() 將返回能夠執(zhí)行那些作為參數(shù)傳遞的 Intent 的所有 Activity 列表,而 queryIntentServices() 則可返回類似的服務(wù)列表。這兩種方法均不會激活組件,而只是列出能夠響應(yīng)的組件。 對于廣播接收器,有一種類似的方法: queryBroadcastReceivers()。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

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

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