Intent被譯做意圖,其實仍是很能傳神的,Intent指望作到的,就是把實現者和調用者徹底解耦,調用者專心將以意圖描述清晰,發送出去,就能夠夢想成真,達到目的。html
這 個解釋仍是有點不太好理解,下面還有一個:Intent是一種運行時綁定(run-time binding)機制,它能在程序運行過程當中鏈接兩個不一樣的組件。經過Intent,你的程序能夠向Android表達某種請求或者意願,Android 會根據意願的內容選擇適當的組件來完成請求。好比,有一個Activity但願打開網頁瀏覽器查看某一網頁的內容,那麼這個Activity只須要發出 WEB_SEARCH_ACTION給Android,Android就會根據Intent的請求內容,查詢各組件註冊時聲明的 IntentFilter,找到網頁瀏覽器的Activity來瀏覽網頁。 這個解釋好像理解起來就容易好多,咱們經過intent傳入某種意圖,而android就會根據這種意圖,自動尋找合適的activity來啓動,若是有 多個條件符合的activity,就以列表的方式讓用戶手動選擇一個。
java
這兩個概念剛開始不太好理解,先看兩個經過intent啓動activity的代碼:android
例一:web
Intent intent = new Intent(); intent.setClass(Context packageContext, OtherActivity.class); startActivity(intent);
例二:瀏覽器
Intent intent = new Intent(); intent.setAction(Intent.ACTION_NEW); startActivity(intent);
從這兩段代碼中能夠明顯看出,一樣是startActivity,但第一個明確指出是啓動OtherActivity,而在第二個例子中,並無明確指出要啓動哪一個activity!服務器
這兩種書寫方式就分別是顯示Intent(例一)、隱式Intent(例二);app
顯式intent是指明確指出此intent是啓動哪一個activity.函數
隱式intent是指並無指出要啓動哪一個activity,而要系統自動去判斷並啓動匹配的activity.測試
有兩種方式來顯示的指示要啓動的Activity:google
方式一:(經過setClassName)
Intent intent = new Intent(); //表示但願啓動com.example.test_permission包中的com.example.test_permission.MainActivity intent.setClassName("com.example.test_permission", "com.example.test_permission.MainActivity"); startActivity(intent);
方式二:(經過SetClass)
Intent intent = new Intent(); intent.setClass(Context packageContext, OtherActivity.class); startActivity(intent);
一樣,setClass(Context packageContext, OtherActivity.class);是指啓動packageContext包裏的OtherActivity.class類;
上面咱們講了隱式intent是要靠系統自動去匹配並啓動某個activity的。那系統是怎樣匹配activity的呢,系統是怎樣知道這個actitiy就是某個intent想要的呢。
某個activity能不能被某個intent激活,要看這個activity是否是符合這個intent的要求,而某個activity能被哪一個intent激活是有定義的,定義就在AndroidManifest.xml
打開AndroidManifest.xml,找到任意一個activity,通常都能看到一段代碼,舉個例子,我隨便複製一個,以下:
<activity android:name=".MainActivity" android:label="@string/app_name" > <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity>
看這裏有一對標籤<intent-filter>……</intent-filter>
在這個標籤裏定義的全部東東都是用來定義該activity能夠被哪些intent激活的,若是匹配,就會被激活!!!!!
在<intent-filter>裏有如下幾個屬性可讓intent來匹配:Action、Category、Data;下面逐一介紹:
該 標識用來講明這個activity能夠執行哪些動做,因此當隱式intent傳遞過來action時,若是跟這裏<intent- filter>所列出的任意一個匹配的話,就說明這個activity是能夠完成這個intent的意圖的,能夠將它激活!!!!
經常使用的Action以下所示:
ACTION_CALL activity 啓動一個電話. ACTION_EDIT activity 顯示用戶編輯的數據. ACTION_MAIN activity 做爲Task中第一個Activity啓動 ACTION_SYNC activity 同步手機與數據服務器上的數據. ACTION_BATTERY_LOW broadcast receiver 電池電量太低警告. ACTION_HEADSET_PLUG broadcast receiver 插拔耳機警告 ACTION_SCREEN_ON broadcast receiver 屏幕變亮警告. ACTION_TIMEZONE_CHANGED broadcast receiver 改變時區警告.
兩條原則:
一條<intent-filter>元素至少應該包含一個<action>,不然任何Intent請求都不能和該<intent-filter>匹配。
若是Intent請求的Action和<intent-filter>中個任意一條<action>匹配,那麼該Intent就能夠激活該activity(前提是除了action的其它項也要經過)。
兩條注意:
若是Intent請求或<intent-filter>中沒有說明具體的Action類型,那麼會出現下面兩種狀況。
若是<intent-filter>中沒有包含任何Action類型,那麼不管什麼Intent請求都沒法和這條<intent-filter>匹配。
反之,若是Intent請求中沒有設定Action類型,那麼只要<intent-filter>中包含有Action類型,這個Intent請求就將順利地經過<intent-filter>的行爲測試。
即這個activity在哪一個環境中才能被激活。不屬於這個環境的,不能被激活。
經常使用的Category屬性以下所示:
CATEGORY_DEFAULT:Android系統中默認的執行方式,按照普通Activity的執行方式執行。表示全部intent均可以激活它 CATEGORY_HOME:設置該組件爲Home Activity。 CATEGORY_PREFERENCE:設置該組件爲Preference。 CATEGORY_LAUNCHER:設置該組件爲在當前應用程序啓動器中優先級最高的Activity,一般爲入口ACTION_MAIN配合使用。 CATEGORY_BROWSABLE:設置該組件可使用瀏覽器啓動。表示該activity只能用來瀏覽網頁。 CATEGORY_GADGET:設置該組件能夠內嵌到另外的Activity中。
注意:
若是該activity想要經過隱式intent方式激活,那麼不能沒有任何category設置,至少包含一個android.intent.category.DEFAULT
在目標<data/>標籤中包含了如下幾種子元素,他們定義了url的匹配規則:
android:scheme 匹配url中的前綴,除了「http」、「https」、「tel」...以外,咱們能夠定義本身的前綴
android:host 匹配url中的主機名部分,如「google.com」,若是定義爲「*」則表示任意主機名
android:port 匹配url中的端口
android:path 匹配url中的路徑
在XML中聲明能夠操做的data域應該是這樣的:
<activity android:name=".TargetActivity"> <intent-filter> <action android:name="com.scott.intent.action.TARGET"/> <category android:name="android.intent.category.DEFAULT"/> <data android:scheme="scott" android:host="com.scott.intent.data" android:port="7788" android:path="/target"/> </intent-filter> </activity>
注意:
這個標識比較特殊,它定義了執行此Activity時所須要的數據,也就是說,這些數據是必須的!!!!!全部若是其它條件都足以激活該Activity,但intent卻沒有傳進來指定類型的Data時,就不能激活該activity!!!!
上面咱們講了一個Activity能被某隱式Intent喚醒的原則,只有這些所有匹配的intent才能喚醒這個Activity,下面咱們就講講怎麼向隱式intent傳遞這些參數,以便與activity匹配將向喚醒。
使用Intent的一個構造方法便可實現傳遞Action參數:
public Intent(String action) { mAction = action; }
對於有以下聲明的Activity:
<activity android:name=".TargetActivity"> <intent-filter> <action android:name="com.scott.intent.action.TARGET"/> <category android:name="android.intent.category.DEFAULT"/> </intent-filter> </activity>
要激活這個Activity,就須要以下這樣構造Intent:(直接向intent中傳遞action的name值)
public void gotoTargetActivity(View view) { Intent intent = new Intent("com.scott.intent.action.TARGET"); startActivity(intent); }
這樣就能夠啓動咱們上面的這個activity了。
注意這裏再次提醒,一個activity能夠有多個action,只要有一個匹配就能夠被啓動。一樣,若是僅指定某個action,而多個activity都具備這個action的話,系統會列出列表供用戶選擇執行哪個activity.
一個intent對象能夠有任意個category。intent類定義了許多category常數.
addCategory()方法爲一個intent對象增長一個category,
removeCategory刪除一個category,
getCategories()獲取intent全部的category.
有兩種傳遞data的方式:
第一種:利用構造函數:
public Intent(String action, Uri uri) { mAction = action; mData = uri; }
第二種:利用Intent::SetData(URI uri)
Intent intent = new Intent("com.scott.intent.action.name"); intent.setData(Uri.parse("scheme://host:port/parth")); startActivity(intent);
舉個例子:(改動下上面的action的例子)
<activity android:name=".TargetActivity"> <intent-filter> <action android:name="com.scott.intent.action.TARGET"/> <category android:name="android.intent.category.DEFAULT"/> <data android:scheme="scott" android:host="com.scott.intent.data" android:port="7788" android:path="/target"/> </intent-filter> </activity>
這個時候若是要啓動這個TargetActivity只指定action就不夠了,咱們須要爲其設置data值,以下:
Intent intent = new Intent("com.scott.intent.action.TARGET"); intent.setData(Uri.parse("scott://com.scott.intent.data:7788/target")); startActivity(intent);
此時,url中的每一個部分和TargetActivity配置信息中所有一致才能跳轉成功,不然就被系統拒絕。
注意:
不過有時候對path限定死了也不太好,好比咱們有這樣的url:(scott://com.scott.intent.data:7788/target/hello)(scott://com.scott.intent.data:7788/target/hi)
這個時候該怎麼辦呢?咱們須要使用另一個元素:android:pathPrefix,表示路徑前綴。
咱們把android:path="/target"修改成android:pathPrefix="/target",而後就能夠知足以上的要求了。
這 個參數不參與匹配activity,而僅做爲額外數據傳送到另外一個activity中,接收的activity能夠將其取出來。這些信息並非激活這個 activity所必須的。也就是說激活某個activity與否只上action、data、catagory有關,與extras無關。而 extras用來傳遞附加信息,諸如用戶名,用戶密碼什麼的。
可經過putXX()和getXX()方法存取信息;也能夠經過建立Bundle對象,再經過putExtras()和getExtras()方法來存取。
經過bundle對象傳遞
發送方
Intent intent = new Intent("com.scott.intent.action.TARGET"); Bundle bundle = new Bundle(); bundle.putInt("id", 0); bundle.putString("name", "scott"); intent.putExtras(bundle); startActivity(intent);
接收方:
Bundle bundle = intent.getExtras(); int id = bundle.getInt("id"); String name = bundle.getString("name");
更多參數傳遞方法見《經過Intent傳遞類對象》
// 調用瀏覽器 Uri webViewUri = Uri.parse("http://blog.csdn.net/zuolongsnail"); Intent intent = new Intent(Intent.ACTION_VIEW, webViewUri); // 調用地圖 Uri mapUri = Uri.parse("geo:100,100"); Intent intent = new Intent(Intent.ACTION_VIEW, mapUri); // 播放mp3 Uri playUri = Uri.parse("file:///sdcard/test.mp3"); Intent intent = new Intent(Intent.ACTION_VIEW, playUri); intent.setDataAndType(playUri, "audio/mp3"); // 調用撥打電話 Uri dialUri = Uri.parse("tel:10086"); Intent intent = new Intent(Intent.ACTION_DIAL, dialUri); // 直接撥打電話,須要加上權限<uses-permission id="android.permission.CALL_PHONE" /> Uri callUri = Uri.parse("tel:10086"); Intent intent = new Intent(Intent.ACTION_CALL, callUri); // 調用發郵件(這裏要事先配置好的系統Email,不然是調不出發郵件界面的) Uri emailUri = Uri.parse("mailto:zuolongsnail@163.com"); Intent intent = new Intent(Intent.ACTION_SENDTO, emailUri); // 直接發郵件 Intent intent = new Intent(Intent.ACTION_SEND); String[] tos = { "zuolongsnail@gmail.com" }; String[] ccs = { "zuolongsnail@163.com" }; intent.putExtra(Intent.EXTRA_EMAIL, tos); intent.putExtra(Intent.EXTRA_CC, ccs); intent.putExtra(Intent.EXTRA_TEXT, "the email text"); intent.putExtra(Intent.EXTRA_SUBJECT, "subject"); intent.setType("text/plain"); Intent.createChooser(intent, "Choose Email Client"); // 發短信 Intent intent = new Intent(Intent.ACTION_VIEW); intent.putExtra("sms_body", "the sms text"); intent.setType("vnd.android-dir/mms-sms"); // 直接發短信 Uri smsToUri = Uri.parse("smsto:10086"); Intent intent = new Intent(Intent.ACTION_SENDTO, smsToUri); intent.putExtra("sms_body", "the sms text"); // 發彩信 Uri mmsUri = Uri.parse("content://media/external/images/media/23"); Intent intent = new Intent(Intent.ACTION_SEND); intent.putExtra("sms_body", "the sms text"); intent.putExtra(Intent.EXTRA_STREAM, mmsUri); intent.setType("image/png"); // 卸載應用 Uri uninstallUri = Uri.fromParts("package", "com.app.test", null); Intent intent = new Intent(Intent.ACTION_DELETE, uninstallUri); // 安裝應用 Intent intent = new Intent(Intent.ACTION_VIEW); intent.setDataAndType(Uri.fromFile(new File("/sdcard/test.apk"), "application/vnd.android.package-archive"); // 在Android Market中查找應用 Uri uri = Uri.parse("market://search?q=憤怒的小鳥"); Intent intent = new Intent(Intent.ACTION_VIEW, uri);
至此本文就結束了。
下一篇用簡單的幾個實例,來具體講解隱式intent的匹配與調用原理。
參考文章 :