Intent過濾

編寫:kesenhoo - 原文:http://developer.android.com/training/basics/intents/filters.html

前兩節課主要講了從一個app啟動另外一個app。但如果我們的app的功能對別的app也有用,那麼其應該做好響應的準備。例如,如果創建了一個social app,它可以分享messages 或者 photos 給好友,那麼最好我們的app能夠接收ACTION_SEND 的intent,這樣當用戶在其他app觸發分享功能的時候,我們的app能夠出現在待選對話框。

通過在manifest文件中的<activity>標籤下添加<intent-filter>的屬性,使其他的app能夠啟動我們的activity。

當app被安裝到設備上時,系統可以識別intent filter並把這些信息記錄下來。當其他app使用implicit intent執行 startActivity() 或者 startActivityForResult()時,系統會自動查找出那些可以響應該intent的activity。

添加Intent Filter

為了儘可能確切的定義activity能夠handle的intent,每一個intent filter都應該儘可能詳盡的定義好action與data。

若activity中的intent filter滿足以下intent對象的標準,系統就能夠把特定的intent發送給activity:

  • Action:一個想要執行的動作的名稱。通常是系統已經定義好的值,如ACTION_SENDACTION_VIEW。 在intent filter中通過<action>指定它的值,值的類型必須為字符串,而不是API中的常量(看下面的例子)

  • Data:Intent附帶數據的描述。在intent filter中通過<data>指定它的值,可以使用一個或者多個屬性,我們可以只定義MIME type或者是隻指定URI prefix,也可以只定義一個URI scheme,或者是他們綜合使用。

Note: 如果不想handle Uri 類型的數據,那麼應該指定 android:mimeType 屬性。例如 text/plain or image/jpeg.

  • Category:提供一個附加的方法來標識這個activity能夠handle的intent。通常與用戶的手勢或者是啟動位置有關。系統有支持幾種不同的categories,但是大多數都很少用到。而且,所有的implicit intents都默認是 CATEGORY_DEFAULT 類型的。在intent filter中用<category>指定它的值。

在我們的intent filter中,可以在<intent-filter>元素中定義對應的XML元素來聲明我們的activity使用何種標準。

例如,這個有intent filter的activity,當數據類型為文本或圖像時會處理ACTION_SEND的intent。

<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"/>
        <data android:mimeType="image/*"/>
    </intent-filter>
</activity>

每一個發送出來的intent只會包含一個action與data類型,但handle這個intent的activity的 <intent-filter>可以聲明多個<action>, <category><data>

如果任何的兩對action與data是互相矛盾的,就應該創建不同的intent filter來指定特定的action與type。

例如,假設我們的activity可以handle 文本與圖片,無論是ACTION_SEND還是ACTION_SENDTO 的intent。在這種情況下,就必須為兩個action定義兩個不同的intent filter。因為ACTION_SENDTO intent 必須使用 Uri 類型來指定接收者使用 send 或 sendto 的地址。例如:

<activity android:name="ShareActivity">
    <!-- filter for sending text; accepts SENDTO action with sms URI schemes -->
    <intent-filter>
        <action android:name="android.intent.action.SENDTO"/>
        <category android:name="android.intent.category.DEFAULT"/>
        <data android:scheme="sms" />
        <data android:scheme="smsto" />
    </intent-filter>
    <!-- filter for sending text or images; accepts SEND action and text or image data -->
    <intent-filter>
        <action android:name="android.intent.action.SEND"/>
        <category android:name="android.intent.category.DEFAULT"/>
        <data android:mimeType="image/*"/>
        <data android:mimeType="text/plain"/>
    </intent-filter>
</activity>

**Note:**為了接受implicit intents, 必須在我們的intent filter中包含 CATEGORY_DEFAULT 的category。startActivity()和startActivityForResult()方法將所有intent視為聲明瞭CATEGORY_DEFAULT category。如果沒有在的intent filter中聲明CATEGORY_DEFAULT,activity將無法對implicit intent做出響應。

更多sending 與 receiving ACTION_SEND intents執行social sharing行為的,請查看上一課:接收Activity返回的結果(Getting a Result from an Activity)

在Activity中Handle發送過來的Intent

為了決定採用哪個action,我們可以讀取Intent的內容。

可以執行getIntent() 來獲取啟動我們activity的那個intent。我們可以在activity生命週期的任何時候去執行這個方法,但最好是在onCreate()或者onStart()裡面去執行。

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    setContentView(R.layout.main);

    // Get the intent that started this activity
    Intent intent = getIntent();
    Uri data = intent.getData();

    // Figure out what to do based on the intent type
    if (intent.getType().indexOf("image/") != -1) {
        // Handle intents with image data ...
    } else if (intent.getType().equals("text/plain")) {
        // Handle intents with text ...
    }
}

返回Result

如果想返回一個result給啟動的那個activity,僅僅需要執行setResult(),通過指定一個result code與result intent。操作完成之後,用戶需要返回到原來的activity,通過執行finish() 關閉被喚起的activity。

 // Create intent to deliver some kind of result data
Intent result = new Intent("com.example.RESULT_ACTION", Uri.parse("content://result_uri");
setResult(Activity.RESULT_OK, result);
finish();

我們必須總是指定一個result code。通常不是RESULT_OK就是RESULT_CANCELED。我們可以通過Intent 來添加需要返回的數據。

**Note:**默認的result code是RESULT_CANCELED.因此,如果用戶在沒有完成操作之前點擊了back key,那麼之前的activity接受到的result code就是"canceled"。

如果只是純粹想要返回一個int來表示某些返回的result數據之一,則可以設置result code為任何大於0的數值。如果我們返回的result只是一個int,那麼連intent都可以不需要返回了,可以調用setResult()然後只傳遞result code如下:

setResult(RESULT_COLOR_RED);
finish();

**Note:**我們沒有必要在意自己的activity是被用startActivity() 還是 startActivityForResult()方法所叫起的。系統會自動去判斷該如何傳遞result。在不需要的result的case下,result會被自動忽略。


书籍推荐