本文主要介紹Intent和Intent Filter的概念及作用、Intent的結構、兩種類型Intent、 Intent和Intent Filter 的匹配規則、利用Intent調用其他常見程序。
1、Intent和Intent Filter的介紹及作用
Android包含四大組件Activity、Service、Broadcast Receiver、Content Provider。其中的Activity、Service、Broadcast Receiver之間如何進行通信,如當前處在Activity A,如何切換到ActivityB,如何啟動一個Service,如何注冊一個Broadcast,如何發送一條短信,如何打開本機的地圖或是瀏覽器呢,這些都要用到Intent。
Intent是抽象的數據結構,包含了一系列描述某個操作的數據,使得程序在運行時可以在程序中不同組件間通信或啟動不同的應用程序。可以通過startActivity(Intent)
啟動一個Activity, sendBroadcast(Intent) 發送廣播發送給感興趣的BroadcastReceiver組件, startService(Intent)啟動service,bindService(Intent, ServiceConnection, int)綁定服務。
Intent Filter顧名思義就是Intent的過濾器,組件通過定義Intent Filter可以決定哪些隱式Intent可以和該組件進行通訊。關於隱式Intent的定義后面會進行介紹,Intent Filter對顯式的Intent不起作用。
2、Intent結構
Intent結構如下
private String mAction; private Uri mData; private String mType; private String mPackage; private ComponentName mComponent; private int mFlags; private HashSet<String> mCategories; private Bundle mExtras; private Rect mSourceBounds;
Intent的主要成員是mAction和mData
Action就是個String類型的字符串,在隱式Intent中用來和filter進行匹配的關鍵指標,如ACTION_VIEW,ACTION_EDIT等,Intent內置了很多Action常量,我們也可以自定義私有Action方便自己進行匹配。
Data為Uri類型的數據,若mType為空通過對mData的解析可以得到數據的類型。
Component表示組件信息,包含context和目標組件的class信息,設置了即為顯示Intent。
Category作為決定哪個組件處理Intent的附屬信息,一個Intent可以添加或刪除多個Category存儲在mCategories。
Flag用於標記如何啟動一個活動,是NEW_TASK還是其他等等,以及啟動后怎么對待這個活動。
Extras為附加信息,會傳遞給目標組件,比如發送郵件,Extras可以存儲郵件收件人地址、內容、主題、附件等信息。
因為Intent Filter和Intent的匹配只有三個字段起作用,所以Intent Filter只包含Actions、Datas、Categorys三個屬性(實際源碼中會將Data划分為多個部分),屬性的意義和Intent相同。不同的是Intent Filter可以包含多個Action、多個Data、多個Category,而Intent除Category可以有多個外,只能有一個Action、一個Data。
3、兩種類型的Intent
對於一個定義好的Intent,Android如何判斷和哪個目標組件通訊呢。Intent分為隱式(implicit)Intent和顯式(explicit)Intent。
顯式Intent通常用於在程序內部組件間通信,已經明確的定義目標組件的信息,所以不需要系統決策哪個目標組件處理Intent,如下
Intent intent = new Intent(DemoList.this, GoogleMapDemo.class); startActivity(intent);
其中DemoList和GoogleMapDemo都是用戶自定義的組件,
隱式Intent不指明目標組件的class,只定義希望的Action及Data等相關信息,由系統決定使用哪個目標組件。如發送短信
Uri uri = Uri.parse("smsto:15800000000"); Intent i = new Intent(Intent.ACTION_SENDTO, uri); i.putExtra("sms_body", "The SMS text"); startActivity(i);
這也是Android系統設計的一個亮點之一,通過隱式的Intent可以方便的調用其他程序的組件,比如調用地圖、短息、打電話、拍照組件為自己的程序所用。這里就涉及下一個問題,系統如何決定目標組件呢?
4、Intent和<intent-filter>的匹配規則
Android系統通過對Intent和目標組件在AndroidManifest文件中定義的<intent-filter>(也可以在程序中定義Intent Filter)進行匹配決定和哪個目標組件通訊。如果某組件未定義<intent-filter>則只能通過顯式的Intent進行通信。Intent的三個屬性用於對目標組件選取的決策,分別是Action、Data(Uri和Data Type)、Category。匹配規則如下
a. Intent定義的Action必須包含在<intent-filter>的Action列表中,若隱式Intent未定義Action系統會報錯。由此可知一個<intent-filter>至少包含一個Action。
b. 未定義Uri和Type的Intent僅可以通過不包含包含Uri和Type的filter;包含了Uri,不包含Type的Intent僅可以通過包含匹配Uri不包含Type的filter;包含了Type不包含Uri的Intent僅可以通過包含了相同Type不包含Uri的filter;同時包含了Uri和Type的Intent僅可以通過相同Type匹配Uri(或不包含Uri但Intent Uri為content:或file:)的filter。
c. Intent若定義了Category(可多個),則所有Category必需包含在<intent-filter>的Category列表中。若Intent未定義Category,則<intent-filter>是否定義Category不影響。
PS:<intent-filter>必須包含<category android:name="android.intent.category.DEFAULT" />才能通過startActivity啟動,所以Activity的<intent-filter>至少包含一個category,Service和BroadcastReceiver不必。
目標組件必須包含同時滿足以上規則的<intent-filter>才能進行匹配。若有多個目標組件同時可以匹配,則系統會提示用戶進行選擇,若沒有目標組件可以匹配系統會進行提示。
如某組件filter如下
<intent-filter android:label="@string/resolve_edit"> <action android:name="android.intent.action.VIEW" /> <action android:name="android.intent.action.EDIT" /> <category android:name="android.intent.category.DEFAULT" /> <data android:mimeType="vnd.android.cursor.item/vnd.google.note" /> </intent-filter>
則{action=android.intent.action.INSERT}不可以通過
{action=android.intent.action.VIEW category=android.intent.category.ALTERNATIVE}不可以通過
{action=android.intent.action.VIEW data=content://com.google.provider.NotePad/notes/{ID}}可以通過
{action=android.intent.action.VIEW data=smsto:15800000000}不可以通過
5、利用Intent調用其他常見程序
a. 發送短信
Uri uri = Uri.parse("smsto:15800000000"); Intent i = new Intent(Intent.ACTION_SENDTO, uri); i.putExtra("sms_body", "The SMS text"); startActivity(i);
b. 打電話
Uri dial = Uri.parse("tel:15800000000"); Intent i = new Intent(Intent.ACTION_DIAL, dial); startActivity(i);
c. 發送郵件
Uri email = Uri.parse("mailto:abc@126.com;def@126.com"); Intent i = new Intent(Intent.ACTION_SENDTO, email); startActivity(i);
或
Intent i = new Intent(Intent.ACTION_SEND); String[] tos = {"abc@126.com"}; String[] ccs = {"def@126.com"}; i.putExtra(Intent.EXTRA_EMAIL, tos); i.putExtra(Intent.EXTRA_CC, ccs); i.putExtra(Intent.EXTRA_SUBJECT, "主題"); i.putExtra(Intent.EXTRA_TEXT, "正文"); i.setType("message/rfc822"); startActivity(i);
d. 拍照
Intent i = new Intent(MediaStore.ACTION_IMAGE_CAPTURE); String folderPath = Environment.getExternalStorageDirectory().getAbsolutePath() + File.separator + "AndroidDemo" + File.separator; String filePath = folderPath + System.currentTimeMillis() + ".jpg"; new File(folderPath).mkdirs(); File camerFile = new File(filePath); i.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(camerFile)); startActivityForResult(i, 1);
e. 瀏覽網頁
Uri web = Uri.parse("http://www.google.com"); Intent i = new Intent(Intent.ACTION_VIEW, web); startActivity(i);
f. 查看聯系人
Intent i = new Intent(); i.setAction(Intent.ACTION_GET_CONTENT); i.setType("vnd.android.cursor.item/phone"); startActivityForResult(i, 1);
其他更多可以見http://www.apkbus.com/forum.php?mod=viewthread&tid=13667&extra=page%3D3%26orderby%3Dlastpost
參考:
http://developers.androidcn.com/reference/android/content/Intent.html
http://developer.android.com/guide/components/intents-filters.html