Intent and Intent Filters

轉載請註明出處:http://blog.csdn.net/zhouli_csdn/article/details/45696591

意圖和意圖過濾器

意圖是一個消息對象你可以從其它組件中發出一個請求動作,通常有三種用法:

  • 啓動一個activity
    • 通過startActivity(intent),intent可以攜帶數據。
    • 如果希望在activity結束時接收一個結果,startActivityForResult,你可以在activity的onActivityResult(int requestCode,int resultCode,Intent data).
  • 啓動service
    • 傳遞Intent,startService。
    • 傳遞Intent,bindService。
  • 發出廣播
    一個廣播消息任何應用程序都可以接收。系統爲一些系統事件提供廣播,例如開機,設備開始充電。
    • sendBroadcast
    • sendOrderedBroadcast
    • sendStickyBroadcast

意圖類型

  • 顯示意圖
    顯示意圖指定了要啓動的組件的名稱(類全稱)。你可以在自己使用它,因爲你知道它的名稱。
  • 隱示意圖
    它不聲明具體的組件名稱,但是你需要聲明一個動作(action),允許其它應用的組件處理它。
    當你啓動一個顯示意圖,系統立即根據intent裏面指定的組件啓動它。
    當你使用隱示意圖,系統會根據其它應用manifest中的意圖過濾器進行匹配。如果匹配到一個意圖過濾器,系統將會把intent傳遞給它並啓動。如果有多個匹配,系統會顯示一個對話框讓用戶選擇。
    一個意圖過濾器是你在manifest中爲組件指定的希望接受的intent類型。如果你不爲一個activity指定任何意圖,那他只能被顯示意圖啓動。
    注意:確保你的應用是安全的,使用顯示意圖啓動service,並且不爲service聲明任何意圖過濾器。使用隱式意圖有安全風險,因爲你不確定到底是什麼service相應了意圖,用戶也看不見什麼service啓動了。
    Android5.0(Api 21),如果你使用隱式意圖bindService,會拋出異常。

創建一個意圖

  • 組件名稱
    如果有名稱,那就是顯示意圖;如果沒有指定名稱,會根據intent的內容決定(action,data,category,etc.)
    setComponent()、setClass()、setClassName()、構造器。
  • action
    • action很大程度上決定了intent其它部分(例如data、extras)的結構
    • 你可以自己指定actions,但是你通常應該使用Intent類內部定義的或者其它類定義的。例如:
      • ACTION_VIEW:當你有一些東西可以通過activity要展示給用戶。(例如:圖片、地圖的地址)
      • ACTION_SEND:也被成爲分享意圖,當你有一些東西可以通過其它app分享。
      • Intent還有很多actions,其他類Settings有actions可以打開系統設置的某一個頁面。
      • setAction()或者構造器指定action
      • 自定義action,要帶上包名:static final String ACTION_TIMETRAVEL = “com.example.action.TIMETRAVEL”;
  • data
    • 一個Uri對象。數據類型通常由action決定。例如:ACTION_EDIT,那麼data應該包含編輯數據的uri。
    • 當創建意圖,指定data的MIME類型很重要。例如一個播放音頻的不能播放視頻即使uri格式相似。有時候,MIME類型可以從 URI 得到例如:content:URI ,暗示數據是contentprovider類型。
    • 只需要設置data uri,使用setData(),只需要設置MIME類型,使用setType()。
    • 注意:如果你需要設置data和type,使用setDataAndType()。如果分別調用setData和setType,它們會相互消除另一個的設置
  • category
    • 包含了應該處理這個Intent的組件的種類的字符串。一個Intent可以包含任意多的category。
      • CATEGORY_BROWSABLE:目標activity可以使用瀏覽器打開一個連接
      • CATEGORY_LAUNCHER:一個任務的初始化activity,被展現在應用的launcher列表中。
      • 更多請查看Intent類
      • 使用addCategory()
        以上三個屬性使Intent的核心。通過它們,系統就可以確定應該啓動哪個應用組件。下面的屬性不會影響:
  • extras
    • 使用putExtra()添加鍵值對、還可以使用putExtras添加Bundle。
    • Intent類有很多標準數據類型
  • flags
    • 可以指定系統如何加載一個activity。(例如activity應該屬於哪一個task),加載後如何對待(例如是否屬於最近的活動列表)查看setFlags().

顯示意圖舉例

// Executed in an Activity, so 'this' is the Context
// The fileUrl is a string URL, such as "http://www.example.com/image.png"
Intent downloadIntent = new Intent(this, DownloadService.class);
downloadIntent.setData(Uri.parse(fileUrl));
startService(downloadIntent);

隱式意圖舉例

注意:如果系統中沒有可以匹配隱式意圖的組件,調用會失敗並且應用會崩潰。可以使用resolveActivity()檢測

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

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

注意:這次,沒有使用URI,因爲intent的數據類型已經指定extras攜帶內容。

迫使使用選擇對話框

如果用戶設置了默認程序,用戶可能希望不同場景使用不同的app(Intent.createChooser):

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);
}

接收隱式意圖

一個應用組件應該爲它能做的每一個任務分開定義intent filters。例如一個activity可以顯示圖片也可以編輯圖片,那就定義兩個filters。當activity啓動後,可以根據intent裏面的內容決定是否展示圖片編輯器。使用intent-filter標籤,你可以在它裏面多次使用action、data、category。

  • action:通過它的name屬性定義動作的名稱,應該使用動作的文字字符串而不是類的常量。
  • data:指定接收數據的類型。可以使用多個URI屬性(scheme、host、port、path、etc.),MIME類型。
  • category:通過它的name屬性定義動作的名稱,應該使用動作的文字字符串而不是類的常量。
    • 注意:如果要接收隱式意圖,必須提供category的CATEGORY_DEFAULT值。
<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>

Filters舉例:

<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>
  • ACTION_MAIN:指定這是主入口
  • CATEGORY_LAUNCHER:這個activity的圖標必須展示在launcher中,如果activity沒有,使用application的。
  • 這兩個必須一起使用使app可以展現在launcher中。
  • 注意:The MIME type, application/vnd.google.panorama360+jpg, is a special data type that specifies panoramic photos, which you can handle with the Google panorama APIs.

使用PendingIntent

PendingIntent是Intent的一個包裝。PendingIntent的主要目的是爲了允許其它應用就像在你自己應用的進程中使用包含的intent。
主要的PendingIntent使用場景:

  • 聲明一個意圖,當用戶在通知欄執行一個動作(系統的NotificationManager執行這個intent)
  • 聲明一個意圖,當用戶在你的AppWidget執行動作(系統的HomeScreen執行這個intent)
  • 聲明一個意圖,在將來的一個指定的時間執行(系統的AlarmManger執行)
  • 創建PendingIntent:
    • PendingIntent.getActivity() 啓動一個activity
    • PendingIntent.getService() 啓動一個service
    • PendingIntent.getBroadcast() 啓動一個廣播
    • 每一個方法有兩個參數,當前app的context和要包含的intent。可以指定標誌intent如何使用(例如intent可以被使用多次)

Resolve Intent

當系統接到一個啓動activity隱式意圖的時候,會在系統中通過比較一下三個屬性查找匹配的:

  • intent action
  • intent data(both URI and data type)
  • intent category

ActionTest

條件 Intent Filter Result
Action 1 >=1 Intent必須比配其中一個action
Action 1 0 fail
Action 0 >=1 pass

CategoryTest

條件 Intent Filter Result
Category >=1 >=1 Intent中所有的category必須與filter中的匹配
Category 0 >=1 pass

注意:系統自動的爲隱式Intent添加了CATEGORY_DEFAULT,所以activity如果想接收隱式Intent,必須包含CATEGORY_DEFAULT。

DataTest

URI匹配:(1表示有;0表示沒有,.表示不確定)

條件 Intent Filter Result
scheme/authority/path 1/./. 1/0/0 Intent只需要包含scheme
scheme/authority/path 1/1/. 1/1/0 需要匹配scheme和authority
scheme/authority/path 1/1/1 1/1/1 三者匹配才pass

Data匹配:

條件 Intent Filter Result
URI/MIME type 0/0 0/0 pass
URI/MIME type 1/0 1/0 只有URI匹配,才pass
URI/MIME type 0/1 0/1 MIME type相同,才pass
URI/MIME type 1/1 1/1 兩者匹配/Intent有一個包含contnet:或者file:的URI而且filter沒有URI

最後一個條件暗示組件的data如果只有MIME type,那麼將默認支持content:和file:,所以組件可以只包含MIME type,例如:

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

包含URI和MIME type的例子,例如下面的支持組件從網絡獲得一個video:

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

意圖匹配

意圖匹配不只是用來啓動一個組件,還可以用來查看設備上組件的一些設定。
例如:Launcher通過查找包含ACTION_MAIN 和CATEGORY_LAUNCHER的intent filter來確定app。
你自己的應用也可以這樣做。
PackageManager有一些查詢方法,queryIntentActivities(),queryIntentServices(),queryBroadcastReceivers(),
還有一些resolve…()方法決定最好的相應組件。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章