今天將對 Implicit Intent 做更深入的探討,昨天的範例中,當我們於 Intent 指定好 ACTION 和對應的 data Uri 後,呼叫 startActivity 將這個 Intent 送給 Android,當系統收到這個 Intent 後,會去檢查它所維護的 Activity List,並找出有哪些 Activity 可以幫忙處理這個 Implicit Intent,為了讓讀者對這個過程能夠瞭解,筆者嘗試寫了一個小的專案「FakeMailApp」,這個 App 可以幫忙寄信,因此若按下「寄信給開發者」,這個 App 也會被列為可處理寄信的 App 之一。
建立新專案的過程就不再贅述,建立好專案後,可於 /FakeMailApp/app/main 下發現一個名為 AndroidManifest.xml 的檔案,這個檔案會記錄這個 App 有哪些 Components,一個 Android App 可能包含四種 Components: Activity, Broadcast Receiver, Service, Content Provider,要宣告這四種 Component,可分別於 application 標籤內使用 activity, receiver, service, provider 標籤來宣告。筆者嘗試修改了 AndroidManifest.xml 的內容,如下所示:
1 <?xml version="1.0" encoding="utf-8"?>
2 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
3 package="lincyu.fakemailapp" >
4
5 <application
6 android:allowBackup="true"
7 android:icon="@drawable/ic_launcher"
8 android:label="@string/app_name"
9 android:theme="@style/AppTheme" >
10 <activity
11 android:name=".MyActivity"
12 android:label="@string/app_name" >
13 <intent-filter>
14 <action android:name="android.intent.action.MAIN" />
15 <category android:name="android.intent.category.LAUNCHER" />
16 </intent-filter>
17 <intent-filter>
18 <action android:name="android.intent.action.SENDTO" />
19 <category android:name="android.intent.category.DEFAULT"/>
20 <data android:scheme="mailto" />
21 </intent-filter>
22 </activity>
23 </application>
24
25 </manifest>
第 10 行我們看到一個 activity 標籤,代表這個 App 有一個 Activity,且從 android:name 屬性可知道其對應的 Activity 類別是 MyActivity,接著我們在 13 ~ 16 行看到一個用 intent-filter 標籤包起來的區塊,由於一個 App 可能包含多個 Activity,第 14 行代表這個 Activity 是這個 App 第一個被啟動的 Activity,第 15 行則代表這個 Activity 會出現在應用程式列表上。
第 17 ~ 21 行的 intent-filter 區塊則是筆者自行加上的,目的是用來告訴系統,這個 Activity 可以幫忙處理寄信,簡單地說,intent-filter 就是告訴系統它可以幫忙處理哪些 Implicit Intent,從第 18 行的 action 標籤和第 20 行的 data 標籤,我們知道這個 Activity 可以處理 ACTION_SENDTO (要注意,AndroidManifest.xml 是一份 XML 文件,不是 Java 程式檔,因此您必須使用常數值,而不能直接使用 Java 常數,故 android:name 屬性的屬性值必須填入 “android.intent.action.SENDTO")。
而第 20 行的 data 標籤,筆者利用 android:scheme 設定 dat Uri 的 Uri scheme 為 mailto,更多 Uri scheme 的說明,讀者可參考維基百科上的說明 [1]。最後第 19 行,每一個通過 startActivity 發出的 Implicit Intent 都至少有一個 Category,即 “android.intent.category.DEFAULT",因此若想處理一個 Implicit Intent,加上第 19 行是必要的。
我們嘗試來驗證這個程式,我們先安裝並執行 FakeMailApp,接著再執行我們的「寶寶生活記錄 App」,並點選「選單」中「寄信給開發者」這個選項,可以發現 FakeMailApp 果然出現了,點選後發現 Activity 確實被啟動了。
這裡順便提醒讀者一件小事情,在應用程式選擇對話框內,有兩個按鈕「一律採用」和「僅限一次」,如果不小心點選了「一律採用」,之後只要寄信都會直接開啟 FakeMailApp,您可以從系統的設定取消這個預設,從「設定」->「應用程式」找到 FakeMailApp,點選後拉到下面 (筆者手機為 HTC M8,不同手機,操作可能會些微不同),在「依預設值啟動」那會出現「您已選擇在進行某些操作時,預設啟動此應用程式」,按下「清除預設值」按鈕就可以了。
最後關於 Implicit Intent 還有一點要說明的,就是除了 ACTION_SENDTO,還有許多系統定義的 ACTION,如 ACTION_VIEW, ACTION_DIAL, ACTION_EDIT 等,但是要注意的是,系統定義的 ACTION 可分兩種:Activity Action 和 Broadcast Action,startActivity 所攜帶的 Implicit Intent,其 ACTION 必須是 Activity Action (Broadcast Action 是讓您寫一個 Broadcast Receiver 去接收系統發出的 Broadcast),請讀者特別注意。
透過 Implicit Intent,搭配適當的 Activity Action,我們可以開啟許多內建應用程式,下面是開啟內建瀏覽器的程式片段,相信讀者可自行閱讀:
1 Uri uri = Uri.parse("http://www.google.com.tw");
2 Intent intent = new Intent();
3 intent.setAction(Intent.ACTION_VIEW);
4 intent.setData(uri);
5 startActivity(intent);
更多 Intent 的用法,讀者可參考盧育聖大師的文章 [2]。
參考資料
[1] URI scheme - Wikipedia, the free encyclopedia, http://en.wikipedia.org/wiki/URI_scheme
[2] ysl 的程式天堂 - Android 應用開發 ‧ 研究 ‧ 與諮詢: Intent 用法大公開, http://ysl-paradise.blogspot.tw/2008/12/intent.html