Intent是一個(gè)消息傳遞對(duì)象,可以使用它向其他組件做一些請求操作挠羔。
盡管 Intent 可以通過多種方式促進(jìn)組件之間的通信许昨,但其基本用例主要包括以下三個(gè):
- 啟動(dòng) Activity
- 啟動(dòng)Service
- 傳遞廣播
Intent 分為兩種:
- 顯示Intent:知道明確的類名。按照類名來做相應(yīng)的操作褥赊。
- 隱式Intent:不知道明確的類糕档。但是知道一些Action等,通過意圖過濾器匹配符合的組件。
顯示Intent
顯示的Intent 比較簡單速那。直接通過類名做相應(yīng)操作即可俐银,顯式 Intent 啟動(dòng) Activity 或服務(wù)時(shí),系統(tǒng)將立即啟動(dòng)對(duì)象中指定的應(yīng)用組件:
// 啟動(dòng)Activity
startActivity(new Intent(this, OtherActivity.class));
// 綁定Service
Intent intent = new Intent(this, BookService.class);
bindService(intent, conn, Context.BIND_AUTO_CREATE);
...
什么樣的Intent屬于顯示的Intent呢端仰?
Intent有個(gè)很重要的屬性: 組件名稱
區(qū)分Intent是顯示還是隱式的捶惜,就是你是否傳遞了** 組件名稱 **。
- 對(duì)應(yīng)在 **Manifest ** 中就是 ** android:name=".act.MainActivity" **荔烧。
- 對(duì)應(yīng)在Java中就是** ComponentName** 這個(gè)類吱七。
如果打開 **new Intent (Context, Activity.class) **的源碼:
public Intent(Context packageContext, Class<?> cls) {
mComponent = new ComponentName(packageContext, cls);
}
代碼就一行,就是根據(jù)傳遞的Context和Class生成** ComponentName** 鹤竭。
因此踊餐,只要指定了** ComponentName** 對(duì)象,就屬于顯示啟動(dòng)臀稚。
所以以下代碼也是屬于顯示啟動(dòng):
Intent intent = new Intent();
// com.demo 是應(yīng)用包名吝岭,在Manifest的package中查看
// com.demo.MainActivity 是要啟動(dòng)的組件的類名
intent.setComponent(new ComponentName("com.demo","com.demo.MainActivity"));
startActivity(intent);
注意1: *如果Activity不是入口Activity或者是一個(gè)Service組件,想要被其他應(yīng)用訪問吧寺,需要加上屬性 android:exported="true" *
注意2: *Service盡量使用顯示啟動(dòng)窜管。為了確保應(yīng)用的安全性,從 Android 5.0(API 級(jí)別 21)開始稚机,如果使用隱式 Intent 調(diào)用 bindService()幕帆,系統(tǒng)會(huì)引發(fā)異常。 *
隱式Intent
如果沒有指定 ComponentName 對(duì)象的Intent就屬于隱式意圖赖条。
隱式的Intent 就比較復(fù)雜了蜓肆,需要了解 Intent-Filter 的匹配規(guī)則。
intent-filter 中包含一下幾個(gè)內(nèi)容:
- <action> 操作
- <data> 數(shù)據(jù)
- <category> 類別
使用隱式 Intent 時(shí)谋币,系統(tǒng)通過將 Intent 中的action仗扬、data、category 與 intent-filter 的內(nèi)容進(jìn)行匹配蕾额,只有action早芭、data、category這三部分都匹配成功诅蝶,這個(gè)intent-filter才算匹配成功退个。
這時(shí)有三種情況:
- 如果 Intent 與 intent-filter匹配,則系統(tǒng)將啟動(dòng)該組件调炬,并向其傳遞 Intent對(duì)象语盈。
- 如果多個(gè) Intent 過濾器匹配的話,則系統(tǒng)會(huì)顯示一個(gè)對(duì)話框缰泡,讓用戶選取相應(yīng)的應(yīng)用刀荒。
- ** 如果匹配不成功,則調(diào)用將會(huì)失敗,且應(yīng)用會(huì)崩潰缠借。**
為了程序的健壯干毅,需要使用Intent 對(duì)象的 **resolveActivity() ** 做一個(gè)檢測。如果結(jié)果為非空泼返,則至少有一個(gè)應(yīng)用能夠處理該 Intent硝逢,且可以安全調(diào)用 startActivity()。 如果結(jié)果為空绅喉,則不應(yīng)使用該 Intent渠鸽,否則會(huì)引發(fā)異常。
匹配是要將代碼中的Intent 與 Manifest中配置的Intent-Filter進(jìn)行匹配
action匹配規(guī)則
Intent可以設(shè)置多個(gè)Action柴罐,** intent-filter **也可以設(shè)置多個(gè)Action徽缚。
匹配規(guī)則:
- Intent中必須至少有一個(gè)Action,并且Intent中的Action必須都要在** intent-filter **中存在
category匹配規(guī)則
category與Action規(guī)則類似丽蝎,但是有點(diǎn)不同:
- 在intent中可以不配置category,但是只要你配置了膀藐,不管配置幾個(gè)屠阻,都必須在Intent-Filter中找到相同項(xiàng)。
注意:
在 startActivity 或者 startActivityForResult 兩個(gè)方法中额各,系統(tǒng)會(huì)默認(rèn)為** Intent 加上一個(gè) android.intent.category.DEFAULT 屬性国觉。所以為了我們定義的組件可以隱式啟動(dòng),我們都必須在 intent-filter 中配置上這個(gè)虾啦,否則 category **無法匹配成功麻诀。
data匹配規(guī)則
data的匹配規(guī)則和前面也是類似的,只是data結(jié)構(gòu)稍微復(fù)雜一些傲醉。
- 只要在Intent-Filter中存在data蝇闭,那么Intent中必須Intent-Filter中的一個(gè)data,才能成功硬毕。
data由一個(gè) URI 和 一個(gè) mimeType組成 呻引。
在data標(biāo)簽中可以只有URI 或者mimeType ,也可以兩者同時(shí)存在吐咳。
data的兩個(gè)屬性介紹:
- mimeType 比較簡單逻悠,類似 text/plain、***image/**** 等韭脊。
-
URI 比較復(fù)雜童谒,結(jié)構(gòu)是:
<scheme>://<host>:<port>/<path>
URI例子:content://com.example.project:200/folder/subfolder/etc
- scheme: content
- host: com.example.project
- port: 200
- path: folder/subfolder/etc
對(duì)應(yīng)到Intent-Filter中就是這幾個(gè)屬性:
<data android:scheme="string"
android:host="string"
android:port="string"
android:path="string"
android:mimeType="string" />
這幾個(gè)屬性都是可選的,但是沪羔,如果沒有指定scheme饥伊,那么這個(gè)URI就是無效的。
URI的scheme 有兩個(gè)默認(rèn)值,content 和 file撵渡。當(dāng)data標(biāo)簽中只有mimeType時(shí)融柬,我們可以使用content 和 file去匹配。
同時(shí)下面兩種寫法是一樣的效果:
// 寫法1
<intent-filter>
<data android:host="www.baidu.com"
android:port="8888"
android:scheme="http" />
</intent-filter>
// 寫法2
<intent-filter>
<data android:scheme="http"/>
<data android:host="www.baidu.com"/>
<data android:port="8888" />
</intent-filter>
同時(shí) Intent.setData() 和 Intent.setType() 趋距,會(huì)相互清空粒氧,所以要同時(shí)設(shè)置data和type需要使用 Intent.setDataAndType()方法。
總結(jié):
想要隱式Intent匹配成功节腐,action和data必須與Intent-Filter匹配外盯,category傳空也是ok的。
若Action有多個(gè)翼雀,匹配一個(gè)即可饱苟。
若想要傳category,傳的category狼渊,必須是相匹配的箱熬。