簡(jiǎn)介
本篇包括Intent、Intent過濾器和常見的Intent
Intent在開發(fā)過程中,有著舉足輕重的作用,最常見的就是界面間的跳轉(zhuǎn)。對(duì)他的翻譯中,我覺得“意圖”解釋的最到位,他用代碼表示我們的想法,并讓系統(tǒng)去執(zhí)行。本篇內(nèi)容包括Intent、Intent過濾器和常見的Intent,下面就依次解釋。
Intent
官方的解釋:Intent是一個(gè)消息傳遞對(duì)象,您可以使用它從其他應(yīng)用組件請(qǐng)求操作。在組件之間的通信主要包括:
-
啟動(dòng) Activity
startActivity(Intent intent)
startActivityForResult(Intent intent, int requestCode)
-
啟動(dòng)服務(wù)
startService(Intent service)
bindService(Intent service, ServiceConnection conn, int flags)
-
傳遞廣播
- sendBroadcast(Intent intent)
Intent又分為顯示Intent和隱式Intent。
顯示是指指定了明確的要啟動(dòng)的組建,即設(shè)置了ComponentName,可以使用 setComponent()、setClass()、setClassName() 或 Intent 構(gòu)造函數(shù)設(shè)置組件名稱;
隱式則就是不指定特定的組件,通過申明一些要執(zhí)行的操作,讓其它組件來處理,這里就設(shè)計(jì)到了Intent過濾器,用來匹配Intent是否有組件去處理,具體匹配規(guī)則在下文再分析。
注意:5.0以后如果使用隱式 Intent 調(diào)用 bindService(),系統(tǒng)會(huì)引發(fā)異常。因?yàn)槟鸁o法確定哪些服務(wù)將響應(yīng) Intent,且用戶無法看到哪些服務(wù)已啟動(dòng)。
Intent包含了:ComponentName、Action、Data、Category、Extra、Flag這幾個(gè)部分,都提供了不同的方法去設(shè)置,不外乎都是setXx或者addXx方法。
使用隱式選擇器時(shí),如果系統(tǒng)中有多個(gè)能匹配上的組件就會(huì)通過一個(gè)對(duì)話框去選擇用哪個(gè)組件去打開。由于系統(tǒng)對(duì)這種默認(rèn)的對(duì)話框提供了記住選擇的功能,所以下次再想選擇就不行了,就像分享功能,這時(shí)候就可以使用Intent.createChooser(Intent target, CharSequence title)去強(qiáng)制打開對(duì)話框。
注意:由于隱式Intent可能匹配不到相應(yīng)的組件,所以我們使用時(shí)最好加上一個(gè)判斷intent.resolveActivity(getPackageManager()) != null,不為空表示能找到目標(biāo)組件
Intent過濾器
隱式Intent,系統(tǒng)是如何找到對(duì)應(yīng)的組件的呢?其實(shí)就是這些組件再M(fèi)anifest文件中定義時(shí),加上了<intent-filter>標(biāo)簽,當(dāng)然可以不定義或者定義一個(gè)或者定義多個(gè)該標(biāo)簽,其中包括了<action>、<category>和<data>三個(gè)標(biāo)簽,三個(gè)標(biāo)簽也是可以不定義的。
<action> 標(biāo)簽,只需設(shè)置name屬性,內(nèi)容可自定義,字符串;
<data> 標(biāo)簽使用一個(gè)或多個(gè)指定數(shù)據(jù) URI 各個(gè)方面(scheme、host、port、path 等)和 MIME 類型的屬性,聲明接受的數(shù)據(jù)類型;
<category> 標(biāo)簽,也是設(shè)置name屬性,內(nèi)容可自定義,字符串。
對(duì)于action,只要組件中某一個(gè)intent-filter中的某一個(gè)action匹配上了即通過;若沒有action標(biāo)簽,則只有當(dāng)intent中也沒有設(shè)置action才算通過;
對(duì)于data,比較復(fù)雜,它包含URI結(jié)構(gòu)和數(shù)據(jù)類型,首先URI的幾個(gè)屬性存在著以下的依賴關(guān)系,
URI結(jié)構(gòu):<scheme>://<host>:<port>/<path>
- 如果未指定scheme,則會(huì)忽略host。
- 如果未指定host,則會(huì)忽略port。
- 如果未指定scheme和host,則會(huì)忽略path。
Intent中的URI與過濾器中的URI規(guī)范進(jìn)行比較時(shí),它僅與過濾器中包含的部分 URI 進(jìn)行比較。所以只要Intent中包含了過濾器中的URI則URI匹配通過;其中path的匹配可包含通配符(*)
URI結(jié)構(gòu)和MIME類型,匹配時(shí),需要分為四種情況,都無、有其一或者都有:
僅當(dāng)過濾器未指定任何 URI 或 MIME 類型時(shí),不含 URI 和 MIME 類型的 Intent 才會(huì)通過測(cè)試。
對(duì)于包含 URI 但不含 MIME 類型(既未顯式聲明,也無法通過 URI 推斷得出)的 Intent,僅當(dāng)其 URI 與過濾器的 URI 格式匹配、且過濾器同樣未指定 MIME 類型時(shí),才會(huì)通過測(cè)試。
僅當(dāng)過濾器列出相同的 MIME 類型且未指定 URI 格式時(shí),包含 MIME 類型、但不含 URI 的 Intent 才會(huì)通過測(cè)試。
僅當(dāng) MIME 類型與過濾器中列出的類型匹配時(shí),同時(shí)包含 URI 類型和 MIME 類型的 Intent 才會(huì)通過測(cè)試的 MIME 類型部分。如果過濾器只是列出 MIME 類型,則假定組件支持 content: 和 file: 數(shù)據(jù)。
對(duì)于category,intent可以不設(shè)置,也可通過,但是若是設(shè)置了,則intent的每個(gè)類別均必須與過濾器中的類別匹配才能通過,而在過濾器中,必須要寫上默認(rèn)的屬性值:android.intent.category.DEFAULT;
綜上,當(dāng)每一項(xiàng)都匹配通過時(shí)即可找到對(duì)應(yīng)的組件。
常用的Intent
1、發(fā)送短信/彩信
public void composeMmsMessage(String message, Uri attachment) {
Intent intent = new Intent(Intent.ACTION_SEND);
intent.setData(Uri.parse("smsto:"));
intent.putExtra("sms_body", message);
intent.putExtra(Intent.EXTRA_STREAM, attachment);//附加的圖像或視頻的 Uri
if (intent.resolveActivity(getPackageManager()) != null) {
startActivity(intent);
}
}
2、打開系統(tǒng)設(shè)置
public void openSettings() {
Intent intent = new Intent(Intent.ACTION_SETTINGS);
if (intent.resolveActivity(getPackageManager()) != null) {
startActivity(intent);
}
}
3、打開電話應(yīng)用
public void dialPhoneNumber(String phoneNumber) {
Intent intent = new Intent(Intent.ACTION_DIAL);
intent.setData(Uri.parse("tel:" + phoneNumber));
if (intent.resolveActivity(getPackageManager()) != null) {
startActivity(intent);
}
}
4、打開瀏覽器瀏覽網(wǎng)址
/**
* @param url 需要以http或https開頭
*/
public static void toHtml(Context context, String url) {
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setData(Uri.parse(url));
context.startActivity(intent);
}
5、打開系統(tǒng)日歷
/**
* 打開系統(tǒng)日歷
*/
public static void callCalendar(Context context) {
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setData(Uri.parse("content://com.android.calendar/time"));
context.startActivity(intent);
}
6、打開系統(tǒng)計(jì)算器
@TargetApi(15)
public static void callCalculator(Context context) {
ArrayList<HashMap<String, Object>> items = new ArrayList<HashMap<String, Object>>();
final PackageManager pm = context.getPackageManager();
List<PackageInfo> packs = pm.getInstalledPackages(0);
for (PackageInfo pi : packs) {
if (pi.packageName.toLowerCase().contains("calcul")) {
HashMap<String, Object> map = new HashMap<String, Object>();
map.put("appName", pi.applicationInfo.loadLabel(pm));
map.put("packageName", pi.packageName);
items.add(map);
}
}
if (items.size() >= 1) {
String packageName = (String) items.get(0).get("packageName");
Intent i = pm.getLaunchIntentForPackage(packageName);
if (i != null)
context.startActivity(i);
} else {
Toast.makeText(context, "沒有安裝計(jì)算器", Toast.LENGTH_SHORT).show();
}
}