在Android中,應用組件也是通過Intent來激活的,其中內容提供器是通過ContentResolver發(fā)出請求的方式來激活的,而Activity、服務和廣播接收器則是通過所謂的Intent異步消息的方式來激活的。
利用Intent激活組件的操作方法有:startActivity(Intent)、startService(Intent)、bindService(Intent, ServiceConnection, int)、sendBroadcast(Intent)等,其中 startActivity()方法用于發(fā)起Activity,startService()方法用于發(fā)起服務,bindService()方法用于綁定服務,而 sendBroadcast()方法則用來向所有關聯(lián)的廣播接收器發(fā)送廣播。
為了能收到Intent消息,AndroidManifest.xml 的“intent-filter”元素必須包含至少一個“action”元素,否則Intent過濾器會過濾掉所有的Intent消息。
在通信過程中,Intent負責對通信消息進行描述,Android則根據(jù)Intent的描述,找到匹配的組件,將 Intent傳遞給匹配的組件,并完成組件的調用。如在文件管理器中,為了打開一個文件,相應Intent的實現(xiàn)如下:
Intent activityIntent = new Intent(Intent.ACTION_VIEW);
activityIntent.setDataAndType(path, mimetype);
activityIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(activityIntent);
如果實在希望了解是否有匹配的組件存在,可以做如下的判斷:
public static boolean isRecognizedFileType(Context context, Uri fileUri, String mimetype)
{
boolean ret = true;
if (D) Log.d(TAG, "RecognizedFileType() fileUri: " + fileUri + " mimetype: " +
mimetype);
Intent mimetypeIntent = new Intent(Intent.ACTION_VIEW);
mimetypeIntent.setDataAndType(fileUri, mimetype);
List< ResolveInfo> list = context.getPackageManager().queryIntentActivities(mimetypeIntent,PackageManager.
MATCH_DEFAULT_ONLY);
if (list.size() == 0)
{
if (D) Log.d(TAG, "NO application to handle MIME type " + mimetype);
ret = false;
}
return ret;
}
因此,Intent在通信過程中起著媒介的作用,專門傳遞組件互相調用的相關信息,實現(xiàn)了調用者與被調用者之間的解耦。
在Android中,Intent攜帶的信息主要有兩種屬性:行為(Action)和數(shù)據(jù)(Data)。其他屬性還有類別(Category)、數(shù)據(jù)類型(Type)、組件(Component)、附加信息(extras)等。
·“Action”屬性是對所執(zhí)行消息主旨的描述,對常見的Action,如查看、編輯、撥號等,Android在系統(tǒng)層面進行了定義,如DIAL_ACTION、MAIN_ACTION、 VIEW_ACTION、EDIT_ACTION。對特殊的行為,允許開發(fā)者自定義。
·“Data”屬性即所執(zhí)行消息涉及的數(shù)據(jù),在Android中采用指向數(shù)據(jù)的URI來表示。如content://contacts/people/1,意思為電話簿中標識符為“1”的條目信息。
·“Category”屬性即所執(zhí)行消息的附加信息。例如,LAUNCHER_CATEGORY 表示Intent 的目標Activity應該作為應用主界面出現(xiàn);而ALTERNATIVE_CATEGORY表示當前的Intent是一系列的可選行為中的一個,這些行為可以在同一塊數(shù)據(jù)上執(zhí)行。
·“Type”屬性顯式指定Intent的數(shù)據(jù)類型(MIME)。一般Intent的數(shù)據(jù)類型能夠根據(jù)數(shù)據(jù)本身進行判定,但是通過設置“Type”屬性,可以顯示指定數(shù)據(jù)類型。
·“Component”屬性指定Intent的目標組件的類名。通常 Android會根據(jù)Intent 中包含的其他屬性的信息,如Action、Sata、Type、Category等屬性進行解析,終找到一個與之匹配的目標組件。但是如果指定“Component”屬性,將直接使用其指定的組件,而不再執(zhí)行上述解析過程。指定該屬性后,Intent的其他所有屬性均變?yōu)榭蛇x屬性。該屬性在Activity的相互調用中經常使用。
·“extras”屬性是其他所有附加信息的集合。使用“extras”屬性可以為組件提供擴展信息,比如如果要執(zhí)行“發(fā)送電子郵件”,可以將電子郵件的標題、正文等保存在“extras”屬性里,傳給電子郵件發(fā)送組件。這給程序開發(fā)帶來了較強的靈活性。該屬性在傳遞數(shù)據(jù)時經常使用。
在Android中,根據(jù)是否聲明“Component”屬性的不同,Intent可以分為顯式Intent和隱式Intent兩種。
其中顯式Intent即指定了“Component”屬性的Intent(代碼實現(xiàn)為通過調用setComponent()方法或setClass()方法)。通過指定具體的組件類,通知應用啟動對應的組件。
隱式Intent即沒有指定“Component”屬性的Intent。這類Intent需要包含足夠的信息,這樣系統(tǒng)才能根據(jù)這些信息,在所有的可用組件中,解析出匹配此Intent的組件。
對于顯式Intent,Android不需要去做解析,因為目標組件已經很明確,Android需要解析的是那些隱式Intent,通過解析,將 Intent傳遞給匹配此Intent的Activity、IntentReceiver或服務。實際的Activity的解析是通過resolveActivity()進行的。
Intent解析機制主要是通過查找已注冊在AndroidManifest.xml中的所有Intent過濾器及其中定義的 Intent,終找到匹配的組件。在解析過程中,Android依賴于Intent的Action、Type、Category等屬性,解析策略如下:
·如果Intent聲明“Action”屬性,則目標組件的Intent過濾器的Action列表中就必須包含該Action,否則不能匹配。
·如果Intent沒有聲明“Type”屬性,系統(tǒng)將從“Data”屬性中得到數(shù)據(jù)的類型。和Action一樣,目標組件的數(shù)據(jù)類型列表中必須包含Intent的數(shù)據(jù)類型,否則不能匹配。
·如果Intent中的“Data”屬性不是“content:”類型的URI,且沒有聲明“Type”屬性,系統(tǒng)將根據(jù)Intent中數(shù)據(jù)的協(xié)議類型(scheme,如http:、mailto:)進行匹配。同上,Intent 的協(xié)議類型必須出現(xiàn)在目標組件的協(xié)議類型列表中。
·如果Intent為“Category”屬性賦予了多個類別值,這些類別必須全部出現(xiàn)在組件的類別列表中。假如Intent中包含了兩個類別:LAUNCHER_CATEGORY 和 ALTERNATIVE_CATEGORY,解析得到的目標組件必須至少包含這兩個類別。
當希望能夠對一個外部的事件(來電、電量發(fā)生變化等)做出響應時,開發(fā)者需要注冊一個Intent過濾器。Intent接收器在關聯(lián)的事件發(fā)生時,會通知應用收到的事件,各種應用還可以通過使用Context.broadcastIntent()方法將Intent 消息廣播給其他應用程序。
Intent過濾器可以在AndroidManifest.xml中注冊,如為了接收打開相應類型的音頻文件的請求,相應的Intent過濾器如下:
< intent-filter>
< action android:name="android.intent.action.VIEW" />
< category android:name="android.intent.category.DEFAULT" />
< data android:scheme="content"/>
< data android:host="media"/>
< data android:mimeType="audio/*"/>
< data android:mimeType="application/ogg"/>
< data android:mimeType="application/x-ogg"/>
< data android:mimeType="application/itunes"/>
< /intent-filter>
部分開發(fā)者可能搞不明白MIME類型的含義,有時可能自我想象的確定MIME類型,殊不知MIME類型是有規(guī)范的,對于每一種文件類型,其標識符唯一。
Intent的標志位主要有FLAG_ACTIVITY_NEW_TASK、FLAG_ACTIVITY_ CLEAR_TOP、FLAG_ACTIVITY_RESET_TASK_IF_NEEDED 、FLAG_ACTIVITY_SINGLE_ TOP等,這些標志位的詳細含義可以參考Android的幫助文檔。