Android组件通信之Intent完全解析

Posted 痕迹天涯119

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Android组件通信之Intent完全解析相关的知识,希望对你有一定的参考价值。

Intent作为android中的信使,被广泛应用于组件间的信息传递,我也曾经写过关于intent的学习笔记,但限于水平,广度和深度实在过于欠缺,这里重新总结整理以备后用。


Intent简介

Intent是一种运行时绑定机制,它能在程序运行过程中连接两个不同的组件。通过Intent,你的程序可以向Android表达某种请求或者意愿,Android会根据意愿的内容选择适当的组件来完成请求。

Intent的构成

action

action是一个字符串,系统预定义了一些action,用来指明要实施的动作是什么,比如说ACTION_VIEW, ACTION_EDIT等,当然我们也可以自定义自己的action

常用action示例:

a. 发送短信

Uri uri = Uri.parse("smsto:15800000000");
Intent i=newIntent(Intent.ACTION_SENDTO, uri);
i.putExtra("sms_body", "The SMS text");
startActivity(i);

b. 打电话

Uri dial = Uri.parse("tel:15800000000");
Intent i=newIntent(Intent.ACTION_DIAL, dial);
startActivity(i);

c. 发送邮件

Uri email = Uri.parse("mailto:abc@126.com;def@126.com");
Intent i=newIntent(Intent.ACTION_SENDTO, email);
startActivity(i);

d. 拍照

Intent i =newIntent(MediaStore.ACTION_IMAGE_CAPTURE);
String folderPath= Environment.getExternalStorageDirectory().getAbsolutePath() + File.separator + "AndroidDemo" +File.separator;
String filePath= folderPath + System.currentTimeMillis() + ".jpg";newFile(folderPath).mkdirs();
File camerFile=newFile(filePath);
i.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(camerFile));
startActivityForResult(i,1);

e. 浏览网页

Uri web = Uri.parse("http://www.google.com");
Intent i=newIntent(Intent.ACTION_VIEW, web);
startActivity(i);

f. 查看联系人

Intent i =newIntent();
i.setAction(Intent.ACTION_GET_CONTENT);
i.setType("vnd.android.cursor.item/phone");
startActivityForResult(i,1);

系统预设了很多action,详情点击:官方Action大全一些常用Action总结

data

要实施操作的数据,常为一个路径或Uri等

data由两部分组成:mimeType和URI ,这里举一个与浏览器交互的例子

Intent intent = new Intent(Intent.ACTION_VIEW);  
intent.setData(Uri.parse("http://www.baidu.com"));  
startActivity(intent);

mineType指的是媒体类型:例如imgage/jpeg,auto/mpeg4和viedo/*等,可以表示图片、文本、视频等不同的媒体格式
uri组成如下

<scheme>://<host>:<port>/[<path>|<pathPrefix>|<pathPattern >]

Scheme:URI的模式,如http、file、content等,若没有指定Scheme则URI其他属性无效
Host:URI主机名,如www.baidu.com,未指定同上
Port:URI端口号,依存于Scheme和Host
Path:完整路径信息
PathPattern:可包含通配符的完整路径,
PathPrefix:路径前缀信息

注意:若Intent Filter的data声明部分未指定uri,则缺省uri为content或file,Intent中的uri的scheme部分需为content或file才能匹配;若要为Intent指定完整的data,必须用setDataAndType方法,究其原因在,setData和setType方法的源码中我们发现:

public Intent setData(Uri data) 
    mData = data;
    mType = null;
    return this;
public Intent setType(String type) 
    mData = null;
    mType = type;
    return this;

category

category是一个字符串,系统预定义了一些category,同时也可以在应用中定义自己的category。
intent有如下常用方法处理category
addCategory(): 为一个intent对象增加一个category,
removeCategory: 删除一个category,
getCategories(): 获取intent所有的category.

component

目标组件,当Intent中指定目标组件时,将直接显式启动。
如下:

        Intent intent = new Intent();
        intent.setComponent(new ComponentName(MainActivity.this,SecondActivity.class));
        startActivity(intent);

其简写形式为

        Intent intent = new Intent(MainActivity.this,SecondActivity.class);
        startActivity(intent);

so,很多时候直接在new Intent的时候填入component组件即可。

extras

附加信息,一般为键对值或Bundle对象,

intent.putExtra()该方法被重载多次,第一个参数为String类型(键),第二个参数几乎可以为任意的基本类型、数组以及Bundle(值);
getIntent().getXXXExtra(“键值”)用于取出对应键对应的值,

经测试,intent.putExtra()完全是可以存取多个的

intent.putExtras()可直接传入Bundle对象,无需键值;
getIntent().getExtras()用于取出Bundle对象


Intent使用分类

Intent主要有显式Intent和隐式Intent,显示Intent主要根据设定有目标的进行调用,而隐式Intent则根据IntentFilter中设定的匹配规则筛选调用。

显式Intent

指明要启动的组件即可,此时不会进行过滤

Intent intent = new Intent(FirstActivity.this, SecondActivity.class);
startActivity(intent);

隐式Intent

依据匹配规则匹配,匹配成功后选择可启动组件进行启动

IntentFilter的匹配规则

Intent解析机制主要是通过查找已注册在AndroidManifest.xml中的所有Intent及其中定义的IntentFilter,最终找到匹配的Intent。

在这个解析过程中,Android是通过IntentFilter的action、data、category这三个属性来进行匹配判断的。一个匹配列表中可以有多个action、data、category,一个Intent只有匹配列表中的任意一组action、data、category属性才能成功启动Activity。此外,一个Activity中可以有多个Intent-filter,而Intent只需要匹配一个IntentFilter的一组属性即可成功启动Activity。

action匹配规则

Intent中的action至少能和过滤规则中的任意一个action匹配才能启动,此外,action区分大小写。

category匹配规则

category与action不同,Intent存在一个默认的category,即category,android.intent.category.DEAFAULT,(仍需要在intentFilter中指明)若Intent没有设置,则必定匹配成功,若Intent设置了category,那么只要有一个category匹配其他的都必须匹配才能启动,否则匹配失败。

下面是常见的category

<intent-filter>
    <action android:name="android.intent.action.MAIN" />
    <category android:name="android.intent.category.LAUNCHER" />
</intent-filter>

其中action表明该Activity是最先启动的,而category则指明该Activity会显示在主程序列表中,二者共同出现缺一不可。

android.intent.action.MAIN 与android.intent.category.LAUNCHER的区别

区别一:
android.intent.action.MAIN决定一个应用程序最先启动那个组件
android.intent.category.LAUNCHER决定应用程序是否显示在程序列表里(说白了就是是否在桌面上显示一个图标)
这两个属性组合情况:
第一种情况:有MAIN,无LAUNCHER,程序列表中无图标
原因:android.intent.category.LAUNCHER决定应用程序是否显示在程序列表里
第二种情况:无MAIN,有LAUNCHER,程序列表中无图标
原因:android.intent.action.MAIN决定应用程序最先启动的Activity,如果没有Main,则不知启动哪个Activity,故也不会有图标出现
所以这两个属性一般成对出现。
如果一个应用中有两个组件intent-filter都添加了android.intent.action.MAIN和
android.intent.category.LAUNCHER这两个属性, 则这个应用将会显示两个图标, 写在前面的组件先运行。
区别二:

android.intent.category.LAUNCHER:android.intent.category.LAUNCHER决定应用程序是否显示在程序列表里,就是android开机后的主程序列表。
android.intent.category.HOME:按住“HOME”键,该程序显示在HOME列表里。

data的匹配规则

如果Intent没有提供type,系统将从data中得到数据类型。和action一样,只要Intent的data只要与Intent Filter中的任一个data声明完全相同,data方面就完全匹配成功。

前面已经说的很详细了,这里再来看一下Intent Filter中指定data的语法:

<data android:scheme="String.“ 
          android:host="String"
          android:port="String"
          android:path="String"
          android:pathPattern="String"
          android:pathPrefix="String"
          android:mimeType="String"/>

这里各个属性无需全部指定

查询是否有Activity可以匹配我们指定Intent的组件

采用PackageManager的resolveActivity或者Intent的resolveActivity方法会获得最适合Intent的一个Activity
调用PackageManager的queryIntentActivities会返回所有成功匹配Intent的Activity

intent.resolveActivity(getPackageManager());
getPackageManager().resolveActivity(intent,PackageManager.MATCH_DEFAULT_ONLY);       getPackageManager().queryIntentActivities(intent,PackageManager.MATCH_DEFAULT_ONLY);

BroadcastReceiver和Service获取成功匹配的组建信息与Activity的方法是类似的

其中,第二个参数flags我们一般使PackageManager.MATCH_DEFAULT_ONLY,为什么要指定该值呢?
其实我们在category的匹配规则中提到过,若Intent匹配过滤规则中的一个category,那么其他的category也都需要匹配,而Intent默认带有一个android.intent.category.DEFAULT的category,所以intentFilter中的category若存在属性但没有android.intent.category.DEFAULT属性将会匹配失败,所以我们设置仅匹配带有android.intent.category.DEFAULT属性category的组件。

intent-filter匹配优先级
action->data->category


参考文章:
http://blog.csdn.net/t12x3456/article/details/7688154
http://blog.csdn.net/mynameishuangshuai/article/details/51673273

以上是关于Android组件通信之Intent完全解析的主要内容,如果未能解决你的问题,请参考以下文章

Android高效安全的本地广播LocalBroadcast完全解析

Android-- Intent(显式和隐式Intent)

Android之四大组件六大布局五大存储 总结

一起学Android之Intent

Android四大组件之Intent

[android开发篇] [应用组件]Intent 和 Intent 过滤器