- Android应用开发教程
- 赵明渊
- 4489字
- 2025-02-21 19:39:29
3.5 Intent属性、过滤器和传递数据
无论是启动Activity、启动Service或者启动BroadcastReceiver等某个组件,Android使用统一的Intent来封装对某个组件的“启动意图”,以利于高层次的解耦。此外,Intent还是组件之间通信的重要媒介。
3.5.1 Intent属性
Intent是连接应用程序的三个核心组件——Activity、Service和BroadcastReceiver的桥梁,Intent负责对应用中操作的动作、动作涉及数据及附加数据进行描述。
Intent类定义在android.content.Intent包中,Intent对象包含Component、Action、Data、Category、Extra及Flag等6种属性。
1.Component
Component(组件)属性用于指定Intent的目标组件,一般由相应组件的包名与类名组合而成。指定了Component属性值之后,Intent的其他属性值都是可选的,此时该Intent就是一个显式Intent。如果不指定Component属性值,则在Androidmanifest中,通过使用IntentFilter来找到一个与之匹配的目标组件,则该Intent就是个隐式Intent。
通过setComponent()方法设置组件属性,通过setClass()、setClassName()方法设置将要启动的组件对应的类,通过getComponent()方法读取组件名。
2.Action
Action(行动)属性用来指明要实施的动作是什么,其属性值是Intent即将触发动作名称的字符串。
Intent定义了用大写字母和下画线组成的动作常量,如表3.1所示。
表3.1 常用动作常量

Action属性可通过setAction()方法来设置,通过getAction()方法来读取。
3.Data
Data(数据)属性用于完成对Intent消息中数据的封装,描述Intent动作所操作数据的URI(Uniform Resource Identifier,通用资源标识符)及MIME(多用途互联网邮件扩展)。
Type(数据类型)属性用于指定URI对应的MIME。
URI格式为:scheme://host:port/path。
获取一个URI的语句格式为:
Uri uri=Uri.parse(<字符串>);
创建一个Intent对象的语句格式为:
Intent intent=new Intent(<动作>,<内容>);
代码:
Uri uri1=Uri.parse(content://contacts/1);
Intent intent=new Intent(Intent.ACTION_VIEW,uri1);
说明:
在上面的代码中,uri1是一个Uri变量,其值为:content://contacts/1,指向手机联系人信息集中的第一个联系人,创建的对象intent显示标识符为“1”的联系人的详细信息。
通过setData()方法设置URI,通过getData()方法读取URI。
4.Category
Category(类别)属性用于描述目标组件额外的附加类别信息,其属性值是一个字符串。
一个Intent中可以包含多个Category。如果没有设置Category属性值,Intent会与在Intent filter中包含“android.category.DEFAULT”的Activity匹配。
Intent定义了类别常量,如表3.2所示。
表3.2 常用类别常量

通过addCategory()方法添加一个Category,通过emoveCategory()方法删除一个Category,通过getCategories()可以获取当前对象的所有Category。
5.Extra
Extra(附加信息)属性用于在多个Action之间进行数据交换。
Extra可以被当作一个Bundle对象,存入多组key-value对(键-值对),这就可以通过Intent在不同Action之间进行数据交换了。
Intent通过调用putExtras()方法来添加一个新的键-值对,而在目标Activity中调用getExtras()方法来获取Extra属性值。
6.Flag
Flag(标志)属性是一些有关系统如何启动组件的标志。指导Android系统启动一个Activity以及Activity启动后对其进行处理。
3.5.2 启动Activity
启动Activity分为显式启动和隐式启动两种。显式启动,必须在Intent中指明启动的Activity对应的类。隐式启动不指明启动的Activity对应的类,系统会根据Intent指定的规则去启动符合条件的Activity。
1.显式启动
使用Intent显式启动Activity,在创建一个Intent后,指定当前的应用程序上下文以及要启动的Activity,把创建好的这个Intent作为参数传递给startActivity()方法。
【例3.3】 显式启动Activity示例。
【解题思路】
在应用项目ExplicitStart中,包含两个Activity,一个是ExplicitStartActivity,另一个是SecondActivity。
程序默认启动的Activity是ExplicitStartActivity,进入ExplicitStartActivity界面,当用户单击“启动Activity”按钮后,程序使用Intent显式启动的Activity是SecondActivity,显式启动Activity的代码如下:

【开发步骤和程序分析】
(1)在Eclipse中创建一个ExplicitStart应用项目,包名为com.application.explicitstart。
(2)在src/com.application.explicitstart包下的ExplicitStartActivity.java文件中,使用Intent显式启动SecondActivity。
在该文件中编辑代码如下:

第19行至第21行(加黑部分),在单击事件onClick(View view)方法中,首先,使用Intent构造方法创建一个实例intent,其中的第一个参数是应用程序上下文ExplicitStartActivity,第2个参数是接收Intent的目标组件SecondActivity,这里使用显式启动方式,直接指明了需要启动的Activity,然后,使用startActivity(intent)方法显式启动SecondActivity。
【运行结果】
应用项目ExplicitStart运行结果如图3.8和图3.9所示。

图3.8 默认启动ExplicitStartActivity

图3.9 显式启动SecondActivity
2.隐式启动
隐式启动不指明启动的Activity对应的类,Android系统会根据Intent指定的属性:Action、Data、Category去启动符合条件的Activity。
隐式启动的优点是不必指明需要启动哪一个Activity,而由系统来决定,这样有利于降低组件之间的耦合度,提高Android组件的可复用性。
【例3.4】 隐式启动Activity示例。
【解题思路】
在应用项目ImplicitStart中,需要启动网页http://www.baidu.com。
在隐式启动Activity中,Intent的动作是Intent.ACTION_VIEW,数据是Web地址,使用Uri.parse(urlString)方法。Android系统在匹配Intent时,根据动作Intent.ACTION_VIEW和数据提供的是Web地址http://www.baidu.com,判定Intent需要启动具有网页浏览功能的Activity。
隐式启动Activity的代码如下:

【开发步骤和程序分析】
(1)在Eclipse中创建一个ImplicitStart应用项目,包名为com.application.implicitstart。
(2)在src/com.application.implicitstart包下的ImplicitStart.java文件中,使用Intent隐式启动Activity,提示用户在http://后输入Web地址,以启动具有网页浏览功能的Activity。
在该文件中编辑代码如下:

第22行至第25行(加黑部分),在单击事件onClick(View view)方法中,首先,使用Intent构造方法创建一个实例intent,其中第一个参数的动作是显示数据Intent.ACTION_VIEW,第2个参数的数据是Web地址,使用Uri.parse(urlString)方法,这里使用隐式启动方式,提示用户在http://后输入Web地址,当用户输入完成Web地址http://www.baidu.com并单击“浏览网页”按钮后,启动具有网页浏览功能的Activity,显示百度页面。
【运行结果】
应用项目ExplicitStart运行结果如图3.10和图3.11所示。

图3.10 提示用户在http://后输入Web地址

图3.11 隐式启动Web页面
3.5.3 Intent过滤器
Intent过滤器(Intent Filter)是一个包含Intent对象的action、data、category属性限制条件的集合,Intent Filter要检测隐式Intent的action、data、category这三个属性,其中任何一项失败,Android系统都不会传递Intent给此组件。
一个组件可以有多个Intent Filter,Intent只要通过其中的某个Intent Filter检测,就可以调用此组件。
Intent过滤器在AndroidManifest.xml文件中进行声明,Intent过滤器使用<intent-filter>子标签来进行声明。
Intent解析机制主要是通过查找已注册在AndroidManifest.xml中的所有Intent Filter及其中定义的Intent属性,最终找到匹配的Intent。
(1)Action检查:一个Intent只能设置一种Action,而一个Intent Filter可以设置多个Action。如果Intent指明定了action,则目标组件的Intent Filter的action列表中就必须包含有这个action,否则不能匹配;如果Intent没有指定action,将自动通过检查。
(2)Category检查:在一个Intent Filter中,可以设置多个Category。如果Intent指定了一个或多个category,这些类别必须全部出现在组件的category列表中。
(3)Data检查:对数据的检查有两部分,一是对数据URI进行检查,一是对数据类型进行检查,对数据URI的检查包括schema、authority和path。
【例3.5】 Intent过滤器示例。
【解题思路】
在应用项目IntentFilterExample中,在AndroidManifest.xml文件<intent-filter>节点的<action>标签、<category>标签和<data>标签,分别定义Intent过滤器的“动作”“类别”和“数据”,以进行相关检查,最终找到匹配的Intent。
【开发步骤和程序分析】
(1)在Eclipse中创建一个IntentFilterExample应用项目,包名为com.application.IntentFilterExample。
(2)在AndroidManifest.xml文件中,分别定义了UserActivity1和UserActivity2的Intent过滤器,包括动作、类别和数据等。
在该文件中编辑代码如下:

① 在第10行到第17行,定义了第1个Activity及其Intent过滤器,第1个Activity名为UserActivity1,第13行到第16行是第1个Activity的Intent过滤器(加黑部分),动作为android.intent.action.MAIN,类别为android.intent.category.LAUNCHER,由此得出,第1个Activity是应用程序启动后显示的默认用户界面。
② 在第18行到第25行,定义了2个Activity及其Intent过滤器,第2个Activity名为UserActivity2,第20行到第24行是第2个Activity的Intent过滤器(加黑部分),过滤器的动作是android.intent.action.VIEW,表示根据Uri协议,以浏览的方式启动相应的Activity;类别是android.intent.category.DEFAULT,表示数据的默认动作;数据的协议部分是android:scheme=“schemodemo”,数据的主机名称部分是android:host=“com.application”。
(3)在src/com.application.IntentFilterExample包下的UserActivity1.java文件中,定义的Intent动作和数据分别与UserActivity2的Intent过滤器定义的动作、数据要求相匹配,该Intent用于启动UserActivity2。
在该文件中编辑代码如下:

① 第21行至第22行,定义了一个Intent用来启动另一个Activity,这个Intent与Activity设置的Intent过滤器是完全匹配的。
② 在第21行定义的Intent(加黑部分),动作为Intent.ACTION_VIEW,Uri是“schemodemo://edu.hrbeu/path”,其中的协议部分为“schemodemo”,主机名部分为“edu.hrbeu”,分别与Intent过滤器定义的动作、数据要求完全匹配。因此,当代码第18行定义的Intent,在Android系统与Intent过滤器列表进行匹配时,会与AndroidManifest.xml文件中UserActivity2定义的Intent过滤器完全匹配。
【运行结果】
应用项目IntentFilterExample运行结果如图3.12和图3.13所示。

图3.12 进入UserActivity1界面

图3.13 进入UserActivity2界面
3.5.4 Activity组件之间通过Intent通信
下面通过一个例题说明Activity组件之间通过Intent通信。
【例3.6】 Activity组件之间通过Intent通信举例。
两个Activity:FirstActivity和SecondActivity,界面上首次进入的Activity为FirstActivity,通过单击按钮来实现FirstActivity和SecondActivity的相互跳转,使用Intent对象实现两个Activity之间的通信。
【解题思路】
在应用项目ActivityIntentExample中,FirstActivity的布局文件为first_main.xml,SecondActivity的布局文件为second_main.xml,FirstActivity的Java代码文件为FirstActivity.java,SecondActivity的Java代码文件为SecondActivity.java。
在FirstActivity和SecondActivity组件中,使用了按钮控件,因此在相应的布局文件中,需要声明按钮控件,其标签为<Button>。
在Java代码文件中,对按钮控件设置监听,使用方法setOnClickListener(),如果监听到按钮被单击,则执行onClick()事件方法定义的操作。
在两个Activity调用中,使用显式启动,两个Activity调用需要返回信息,使用startActivityForResult()方法发送Intent对象,startActivityForResult()方法的格式如下:

如果是从A发送B,然后从B返回到A,并且需要传递信息,则在A代码中使用startActivityForResult()方法发送Intent到B,并且重写onActivityResult()方法用于处理返回的数据;在B代码中使用setResult()方法准备好回传的数据,并且使用finish()方法将打包好的数据发回给A,并运行A中的onActivityResult()部分代码。
【开发步骤和程序分析】
(1)在Eclipse中创建一个ActivityIntentExample应用项目,包名为com.application.activityintentexample,有两个Activity:FirstActivity和SecondActivity。
(2)设计布局。
布局文件为first_main.xml和second_main.xml。
在res/layout目录中,编写FirstActivity的布局文件first_main.xml,定义了一个“进入SecondActivity”按钮。
在该文件中编辑代码如下:

第7行至第10行,定义了一个按钮,其中,第7行定义该按钮的id变量名为button1,并添加到R.java文件中,为Java代码提供调用,第10行定义该按钮显示文本内容为“进入SecondActivity”。
在res/layout目录中,编写SecondActivity的布局文件second_main.xml,定义了一个“返回FirstActivity”按钮。
在该文件中编辑代码如下:

第5行至第8行,定义一个按钮,其中,第5行定义该按钮的id变量名为button2,并添加到R.java文件中,第8行定义该按钮显示文本内容为“返回FirstActivity”。
(3)在包com.application.activityintentexample下的FirstActivity.java文件中,加载first_main.xml布局文件,使用startActivityForResult()方法发送Intent1到SecondActivity,并重写onActivityResult()方法用于处理返回的数据。
在该文件中编辑代码:


① 第17行至第27行(加黑部分),创建一个监听listener1,同时定义一个onClick事件,在事件中定义了当监听到按钮被单击,则进行相应的操作。其中:
- 第20行创建一个Intent对象,对象名为intent1,其动作值为FirstActivity.this,数据值为SecondActivity.class,这是使用Intent显式启动Activity。
- 第23行向intent1中添加附加信息:一组键-值对的Bundle信息,其名为“firstactivity”,值为“从FirstActivity进入--”。
- 第25行使用startActivityForResult()方法发送intent1对象,同时发送一个请求码REQUEST_CODE给SecondActivity。
② 第35行至第49行(加黑部分)重写onActivityResult()方法,通过判断请求码值和返回码值,来确定是否正确获得回传数据,如果是正确的,则取出回传数据并显示在标题栏中。
(4)在包com.application.activityintentexample下的SecondActivity.java文件中,加载second_main.xml布局文件,使用setResult()方法准备好回传的数据,并且使用finish()方法将打包好的数据发回给FirstActivity。
在该文件中编辑代码:


① 第18行至第35行(加黑部分),创建一个监听listener1,同时定义一个onClick()方法,在方法中定义了当监听到按钮被单击,则进行相应的操作。其中:
- 第21行和第24行创建一个Bundle对象,对象名为bundle,并将一组键-值对保存到其中,其名为“store”,其值为“自SecondActivity返回--”。
- 第26行创建一个Intent对象,对象名为intent2。
- 第28行向intent2中添加附加信息,此附加信息是已保存在bundle中的键-值对信息。
- 第30行是打包回传的数据,包括返回码值RESULT_OK和intent2对象。
- 第33行将打包好的数据发回给FirstActivity,并且运行FirstActivity.java中onActivityResult()里面的代码。
② 第40行至第45行(加黑部分)从FirstActivity的intent1对象中取出附加信息赋值给extras,如果其键-值对非空,则取出名为“firstactivity”的对应值给字符串变量data,并将data的值显示在标题栏中。
(5)编写根目录下的AndroidManifest.xml文件的代码,增加Activity组件SecondActivity的声明。

【运行结果】
应用项目IntentFilterExample运行结果如图3.14~图3.16所示。

图3.14 首次进入“查看信息内容页面”

图3.15 单击“进入”按钮后进入“显示信息内容页面”

图3.16 单击“返回”按钮后返回“查看信息内容页面”