我们知道,Intent 是一个消息传递对象,使用它可以向其他Android组件请求操作。Intent的基本用途主要包括:启动 Activity、启动服务、传递广播。Intent分为显式Intent和隐式Intent。下面我通过启动Activity来讲解学习Intent。
Intent对象可以封装传递下面6种信息:
下面来讲解这些信息
1、组件名称(CompomentName)
组件名称指定要访问的组件,但也是构建显式 Intent 的一项重要信息,如下所示:
Intent intent = new Intent(LoginActivity.this, HomeActivity.class); startActivity(intent); |
这样我们就启动了HomeActivity组件。
通过构造函数指定组件名称是我们常用的方式,此外还可以通过以下三种方法指定组件名称
Intent setClass (Context packageContext, Class> cls); Intent setClassName (Context packageContext, String className); Intent setClassName (String packageName, String className); Intent setComponent (ComponentName component) |
这里首先需要说明是的CompomentName对象,它定义了一个组件的基本信息,通过Android的源代码我们可以看到,其实不论哪种方法,最终Intent都会创建一个CompomentName对象封装被调用的组件信息。
其次我们来看一下Intent setClassName (String packageName, String className);这个方法。packageName指的是组件所属APP的包名。也就是AndroidManifest.xml中指定的包名,如下图所示:
最后,需要说明的是,如果传递字符串形式的className,必须指定类的全名,包括类所属的命名空间。下面给出了一个样例代码:
Intent intent = new Intent(); intent.setClassName("com.practise.salary.nvwa", "com.practise.salary.nvwa.HomeActivity"); startActivity(intent); |
设置Intent的组件名称,调用相关的组件,我们称为显式调用,一般用于调用APP自身的组件,当然,我们也可以通过显式调用其他APP的组件,后面讲解显示调用时,我们在来学习。
2、动作(Action)
所谓动作就是与Activity、Service、BroadcastRecvier绑定的一个字符串,通常在AndroidManifest.xml声明组件时,设置动作参数,如下图所示:
我们可以通过设置Action属性,调用相关的组件,这称为隐式调用。
一般我们通过Intent的setAction方法设置Intent的动作,这样系统会根据动作中指定的字符串查找匹配的组件。如下所示代码:
Intent intent = new Intent(); intent.setAction("android.intent.action.MAIN"); startActivity(intent); |
当我们定义自己的操作,建议将应用的软件包名称作为前缀,动作名称用大写。
3、种类(Category)
运行上面的代码,大家会发现,弹出了一个选择框,选在调用那个组件,如下图所示:
之所以会出现这种情况,是因为动作“android.intent.action.MAIN”对应的组件不止一个,Android系统无法判断到底调用那个组件(详细的筛选过程将在后面过滤规则中讲解)。
Intent的Category的就是为了解决这类冲突问题的,Category的设置也是在AndroidManifest.xml文件中完成,如下图所示:
Category也是一个字符串,我们可以通过addCategory为Intent添加Category,可以添加多个Category,如下面代码所示:
Intent intent = new Intent(); intent.setAction("com.practise.salary.nvwa.action.HOME"); /* 我们可以不用手动添加android.intent.category.DEFAULT,系统会自动添加这个Category */ intent.addCategory("android.intent.category.DEFAULT"); startActivity(intent); |
我们可以通过文件夹、文件类比Category和Action。
4、数据(Data)
在Intent的隐式调用中,系统要根据请求对满足条件的组件进行筛选,这就是Intent的筛选机制。筛选条件除了Action、Category外,还有一个就是Data。此外Data还承担了简单的数据传递工作。
组件Data的申明如下图所示:
下面我们学习一下Intent的Data属性。
Data包括MIME Type和URI。
MIME Type指数据的类型,例如:video/mp4,video/avi通常我们通过
Intent setType (String type) 或者 Intent setTypeAndNormalize (String type) |
完成MINE Type的设置。不同之处在于setTypeAndNormalize可以规范MINE Type。
URI,统一资源标识符(Uniform Resource Identifier,或URI)是一个用于标识某一资源名称的字符串,URI可以表示成如下格式:
scheme://host:port/path |
其中
我们常见的URL地址就是一种特殊的URI。
我们可以通过
Intent setData (Uri data) Intent setDataAndNormalize (Uri data) |
来设置Intent的URI,注意此处需要传递的是一个Uri对象,该对象封装了具体的URI,我们采用如下静态方法江URI字符串转换成URI对象。
Uri parse (String uriString) |
此外我们还可以调用setDataAndType一次性设置URI和MIME Type。
Intent setDataAndType (Uri data, String type) Intent setDataAndTypeAndNormalize(Uri data, String type) |
需要注意的是,当我们调用setType方法设置MIME Type,会自动清理URI的属性值,当调用setData方法来设置URI时,会自动清理MIME Type的值,如果要同时设置URI和MIMIE Type,必须使用setDataAndType方法。
关于如何通过Data进行过滤,后面我们会讲到,下面我们通过一个样例来讲解如何通过Data完成简单的数据传递。
我们通过显示调用Intent同时设置Intent的Data。代码如下:
Intent intent = new Intent(LoginActivity.this, HomeActivity.class); intent.setDataAndType(Uri.parse("content://findUser/20180910"), "nvwa/user"); startActivity(intent); |
在被调用的HomeActivity中,我们通过getItent()获取传递来的Intent。然后我们就可以通过
Uri getData () 或 String getDataString () |
获取URI,有了URI我们就可以解析出其中数据。下面给出被调用的组件的样例代码
Intent intent = getIntent(); Uri uri = intent.getData(); Log.v("URI参数传递", uri.getPath()); |
输出结果如下图所示:
Uri类提供了更多的方法用于处理Uri值,可参考Uri相关的帮助 https://developer.android.google.cn/reference/android/net/Uri。
5、附件信息(Extra)
通过Data只能传输比较简单的数据,Intent主要通过Extra完成组件之间的数据传递。
调用方通过intent的putExtra设置数据,被调用的组件通过getXXXExtra获取数据,代码如下所示:
调用方传递参数
Intent intent = new Intent(LoginActivity.this, HomeActivity.class); intent.putExtra("userName", "zhangw"); intent.putExtra("loginTime", Calendar.getInstance()); startActivity(intent); |
被调方获取参数
Intent intent = getIntent(); Log.v("Extra数据传递", intent.getStringExtra("userName")); |
我们分析Android代码可以发现,其实通过Exctra传递的是一个Bundle,我们可以把Bundle理解成一个键值对,他通过putXXX设置数据,通过getXXX读取数据。我们可以自己定义一个Bundle对象,进行数据的传递,下面给一个样例程序。
调用方传递参数
Bundle bundle = new Bundle(); bundle.putString("userName", "account"); bundle.putSerializable("loginTime", Calendar.getInstance()); intent.putExtras(bundle); |
被调方获取参数
Intent intent = getIntent(); Bundle bundle = intent.getExtras(); Log.v("登录时间", bundle.getSerializable("loginTime").toString()); |
输出结果如下图:
注意,调用方通过intent的getExtras获取传递的来的bundle。
6、标记(Flag)
Intent通过
Intent setFlags (int flags) |
设置标记。 关于标记的用法,后面我们用到后再给大家将,这并不表示这个概念不重要。
(张伟:2018年9月27日)
(转载时请注明来源)