經過Intent傳遞類對象

1、Intent是什麼

一、定義

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與隱式Intent

這兩個概念剛開始不太好理解,先看兩個經過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.測試

三、顯式Intent小結

有兩種方式來顯示的指示要啓動的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類;

2、針對隱式intent,Activity的匹配原則

上面咱們講了隱式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、CategoryData;下面逐一介紹:

一、Action:該activity能夠執行的動做

該 標識用來講明這個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>的行爲測試。

二、Category:於指定當前動做(Action)被執行的環境

即這個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  執行時要操做的數據

在目標<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!!!!

3、Intent隱式傳遞方法

上面咱們講了一個Activity能被某隱式Intent喚醒的原則,只有這些所有匹配的intent才能喚醒這個Activity,下面咱們就講講怎麼向隱式intent傳遞這些參數,以便與activity匹配將向喚醒。

一、Action

使用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.

二、Category

一個intent對象能夠有任意個category。intent類定義了許多category常數.

  • addCategory()方法爲一個intent對象增長一個category,

  • removeCategory刪除一個category,

  • getCategories()獲取intent全部的category.

三、Data

有兩種傳遞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",而後就能夠知足以上的要求了。

四、Extras

這 個參數不參與匹配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傳遞類對象》


五、附《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的匹配與調用原理。

參考文章 :

《Android中Intent組件詳解》

《android Intent機制詳解》

《基礎總結篇之九:Intent應用詳解》

《Intent詳解》

《Intent總結》

《Intent中的四個重要屬性——Action、Data、Category、Extras》

相關文章
相關標籤/搜索