Intent可以翻译为意图,它负责对应用中操作的动作及动作所涉及的数据进行描述,Android根据Intent的描述,找到相应的组件,将这个Intent传递给调用的组件,从而完成组件的调用。一个Intent对象其实就是信息的捆绑,它包含了接收该Intent的组件所需要的信息。通常,Intent对象包括如下的一些属性:
l 组件名称(ComponentName)
组件名称即为ComponentName对象,该对象包含了目标组件的类名和所属包名。组件名称是可选的,如果设定了的话,Intent对象会被传给指定类的一个实例。如果不设定,则Android使用其他信息来定位合适的目标。组件名称是使用setComponent(),setClass()或setClassName()来设定,使用getComponent()来获取。
l 动作(Action)
动作即为Intent要采取的行动。用一个字符串表示,Android提供了很多自带的动作,可以浏览网页、发送短信等,也可以自己定义Intent动作,要注意的是,要养成良好的习惯,用Java包名的命名方式来命名,因为系统要求动作名是独一无二的。
l 数据(Data)
即为动作要操作的数据,Android中使用URI的方式来指定一个数据。例如,如果Action为ACTION_EDIT,那么Data将包含待编辑的数据URI。如果Action为ACTION_CALL,Data将为tel:电话号码的URI。如果Action为ACTION_VIEW,则Data为http:网络地址的URI。
l 类别(Category)
即为执行动作的附加信息。举几个例子,LAUNCHER_CATEGORY表示Intent的接收者应该作为顶级的launcher。LAUNCHER_CATEGORY表示当前的Intent是多个可选Intent动作中的一个。
l 数据类型(Type)
显示指定Intent的数据类型(MIME)。一般Intent的数据类型能够根据数据本身进行判定,但是通过设置这个属性,可以强制采用显示指定的类型。
l 附加信息(Extras)
使用Extras可以为组件提供扩展信息,例如,如果要执行“发送电子邮件”这个动作,可以将电子邮件的标题、正文等保存在extras里,传给电子邮件发送组件。
通过Intent对象的这些属性,Intent即可对一次组件通信的动作、动作涉及的数据以及附加信息进行描述,Android系统则根据此Intent的描述,负责找到对应的组件,将Intent传递给该组件,并完成组件的调用。
6.2 显示启动Activity并传递数据
很多时候,应用程序并不是只有一个Activity,这就需要使用Intent实现Activity间的跳转。与此同时,经常会需要在两个Activity之间传递数据。用Intent启动Activity的方式有两种,显示启动和隐式启动。本节介绍如何显示地启动Activity。
所谓显示启动,即直接指明需要启动的Activity。启动一个Activity的步骤如下:
(1) 创建一个Intent对象
(2) 指定当前Activity上下文,即要启动的Activity
(3) 调用startActivity()方法启动Activity,参数为Intent对象
实现这3个步骤只需要实现如下两行代码:
Intent intent = new Intent(CurrentActivity.this,SecondActivity.class);
startActivity(intent);
那么如何在Activity之间传递数据呢?只要在需要传递数据的Activity中使用Intent的putExtra方法,将一个值以键值对的形式附加到Intent对象,再在需要接收这些数据的Activity中使用getXXXExtra方法,即可从启动该Activity的Intent中获取附加的数据,其中XXX为数据类型。
6.3 隐式启动Activity和Intent过滤器IntentFilter
所谓的隐式启动,即不指定要启动的Activity,而由Android系统来决定。Android中应用都是平行的,也就是说没有系统中任何的内容都可以看成一个应用,任何一个应用都可以由第三方软件来实现。比如拨号软件,短信软件等。
这一过程是怎么实现的呢?隐式启动Activity时,Android系统解析启动该Activity的Intent,并根据一定规则对Intent和Activity进行匹配,使Intent上的动作、数据与某些Activity完全吻合。匹配的Activity可以来自应用程序本身,也可以是Android系统内置的,还可以是第三方应用程序。
隐式启动的方法也非常简单,通常只需要实现Intent的另一个构造函数来创建Intent对象即可,而且同样是使用startActivity方法来启动Activity。如下代码会启动系统内置浏览器访问Google:
Intent intent = new Intent(Intent.ACTION_ VIEW,Uri.parse(“http://www.google.com”));
startActivity(intent);
这段代码中,匹配了一个Intent动作,ACTION_VIEW,代表浏览网页。而通过URI数据类型来匹配该动作。这里UrI是一个Web地址。表6.3为Android中提供的一些常用动作常量。
表6.3 Android中提供的一些常用动作常量
动作 | 说明 |
ACTION_ANSWER | 打开接听电话的Activity,默认为Android内置的拨号盘界面 |
ACTION_CALL | 打开拨号盘界面并拨打电话,使用URI中的数字部分作为电话号码 |
ACTION_DELETE | 打开一个Activity,对所提供的数据进行删除操作 |
ACTION_DIAL | 打开内置拨号盘界面,显示URI中提供的电话号码 |
ACTION_EDIT | 打开一个Activity,对所提供的数据进行编辑操作 |
ACTION_INSERT | 打开一个Activity,在提供数据的当前位置插入新项 |
ACTION_SEND | 启动一个可以发送数据的Activity |
ACTION_VIEW | 最常用的动作,对以URI方式传送的数据,根据URI协议部分以最佳方式启动相应的Activity进行处理。对于http://address将打开浏览器查看,对于tel:address将打开拨号呼叫指定的电话号码 |
ACTION_WEB_SEARCH | 打开一个Activity,对提供的数据进行Web搜索 |
通过设置Intent的动作属性来启动某些Android自带应用的Activity。当然也可以用隐式启动来启动自己的Activity。要注意的是,隐式启动Activity的Intent,除了可以进行Action动作的匹配外,还可以进行Category和Data匹配,这三者可以是全部或者部分匹配,Intent对象中的其他两个属性并没有作用。如何根据Intent的这些属性来启动特定的Activity呢?这就需要使用IntentFilter。
IntentFilter即为一个Intent过滤器。Activity、Service和BroadCastReceiver都可以有多个IntentFilter来告知系统它们能接受什么样的隐式Intent。当然显示Intent不用考虑IntentFilter。
Android注册一个IntentFilter非常简单,只需要在AndroidManifest.xml文件中操作即可。具体方法为,在需要注册IntentFilter的组件(如Activity)节点下增加一个<Intent-filter>节点。<intent-filter>节点相应的支持<action>标签、<category>标签和<data>标签,这些标签和Intent对象的属性是一致的。在组件注册过IntentFilter后,Intent需要去匹配这些IntentFilter。这一过程称为Intent解析。解析的匹配原则如下:
(1) Android会把当然系统中所有应用的包的IntentFilter集合在一起,形成一个过滤列表。这样Intent可能会匹配很多系统应用甚至是第三方应用。
(2) 匹配时,Android会将Intent与所有IntentFilter的Action和Category进行匹配,相符的才能通过过滤。没有指定“动作”的Intent过滤器可以匹配任何的Intent,但是没有指定“类别”的Intent过滤器只能匹配没有“类别”的Intent。
(3) Intent的数据URI将与<data>标签中的内容相匹配。但<data>标签声明多个属性的时候,如host、mimetype等,则需要全部匹配。
6.4 获取Activity返回值
很多时候,在从一个Activity跳转到另一个Activity再返回该Activity的时候,需要回传数据。这时候就需要用startActivityForResult方法来启动Activity。
startActivityForResult(Intent,requestCode)方法有两个参数。第一个参数用于决定要启动哪个Activity,第二个参数是唯一标识子Activity的请求码。
再启动完子Activity后,需要在子Activity中设置返回值。通过setResult方法来完成该操作,setResult方法同样有两个参数。第一个参数为结果码,第二个参数即为回传的数据。其中的结果码表明了子Activity的返回状态,通常为Activity.RESULT_OK或者Activity.RESULT_CANCLED,也可以是自定义的结果码。结果码均为整数类型。要注意的是调用setResult方法必须在Activity调用finish()之前。传回的数据一般使用URI的方式,也可以传递一些Extra集合的额外信息。
最后一步当然是获取返回值了。如果需要在父Activity中取得子Activity的返回值,需要重载onActivityResult方法。该方法有3个参数,第一个参数requestCode,用来表示是哪一个子Activity的返回值,和startActivityForResult中的标识相对应。第二个参数resultCode用于表示子Activity的返回状态,和setResult方法中的结果码相对应。
首先创建父Activity,里面有两个Button,分别用来启动不同的字Activity。并且重载onActivityResult()方法,在里面处理返回的数据,用一个TextView显示它。实现代码如下:
public class MainActivity extends Activity{
//声明两个常量,用作请求码
privatestatic final int ACTIVITY2 = 1;
privatestatic final int ACTIVITY3 = 2;
//声明控件对象
privateTextView tv;
privateButton button2, button3;
@Override
protectedvoid onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//得到控件对象
tv= (TextView) this.findViewById(R.id.textView1);
button2= (Button) this.findViewById(R.id.button2);
button3= (Button) this.findViewById(R.id.button3);
//为按钮绑定监听器
button2.setOnClickListener(newOnClickListener() {
@Override
publicvoid onClick(View arg0) {
//创建Intent对象
Intentintent02 = new Intent(MainActivity.this, SecondActivity.class);
startActivityForResult(intent02,ACTIVITY2);
}
});
button3.setOnClickListener(newOnClickListener() {
@Override
publicvoid onClick(View arg0) {
//创建Intent对象
Intentintent03 = new Intent(MainActivity.this, ThirdActivity.class);
startActivityForResult(intent03,ACTIVITY3);
}
});
}
/**
* 重写该方法,取得子Activity的返回值
*/
@Override
protectedvoid onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode,resultCode, data);
switch(requestCode) {//判断是哪个Activity返回的值
caseACTIVITY2:
if(resultCode== RESULT_OK) {
Urivalue = data.getData();//取得数据
tv.setText("这是Activity02传来的数据" +value.toString());
}else{
tv.setText("Activity02未传值");
}
break;
caseACTIVITY3:
if(resultCode== RESULT_OK) {
Urivalue = data.getData();//取得数据
tv.setText("这是Activity03传来的数据" +value.toString());
}else{
tv.setText("Activity03未传值");
}
break;
default:
break;
}
}
}
代码解释:
在Button的监听事件中以startActivityForResult的方式启动,并设置请求码。在onActivityResult方法中通过设置请求码判断是哪一个Activity返回的值。并且判断resultCode,进行进一步区分。
在两个子Activity之间的操作基本相同,这里给出Activity02的代码。代码中将输入框的值通过setResult方法返回父Activity,并设置结果码。实现代码如下:
public class SecondActivity extendsActivity {
//声明控件对象
privateEditText ed;
privateButton button,button_cancle;
@Override
protectedvoid onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_second);
//得到控件对象
ed= (EditText) this.findViewById(R.id.editText1);
button= (Button) this.findViewById(R.id.button);
button_cancle= (Button) this.findViewById(R.id.button_cancle);
//分别为两个按钮绑定监听器
button.setOnClickListener(newOnClickListener() {
@Override
publicvoid onClick(View arg0) {
//取得EditText中的数据
Stringcontent = ed.getText().toString();
//创建一个Uri对象
Uridata = Uri.parse(content);
//创建一个Intent对象
Intentintent = new Intent(null, data);
//设置需要传递的值和结果码
setResult(RESULT_OK,intent);
//关闭该Activity
finish();
}
});
button_cancle.setOnClickListener(newOnClickListener() {
@Override
publicvoid onClick(View arg0) {
//只设置结果码
setResult(RESULT_CANCELED);
//关闭该Activity
finish();
}
});
}
}
最后运行效果如图6.4.1和图6.4.2
图6.4.1
图 6.4.2