前言
在上一节中我们了解了Activity如何在应用中正常运行,如何使用Toast发送通知以及怎样使用AppcompatActivity提供自带的标题栏中的Menu,这次我们来了解多个Activity之间如何进行信息传递。
正文
什么是Intent?
正如字面意思,Intent可以作为意图来传递,一般可以被用作启动活动,服务以及广播。并且Intent除了可以传递意图,还能够在组件之间传递数据,当然,Intent的传递也是可以跨应用的,如果目标应用的活动是对外暴露的。
我们来看看官网是如何介绍Intent的:An intent is an abstract description of an operation to be performed. It can be used with
startActivity()
to launch anActivity
, broadcast Intent to send it to any interestedBroadcastReceiver
components, andstartService(Intent)
orbindService(Intent, ServiceConnection, int)
to communicate with a backgroundService
.
An Intent provides a facility for performing late runtime binding between the code in different applications. Its most significant use is in the launching of activities, where it can be thought of as the glue between activities. It is basically a passive data structure holding an abstract description of an action to be performed.显示Intent与隐式Intent
当我们想要使用Intent来启动其他的组件的时候,可以以两种方式启动,第一种就是显式Intent,第二种是隐式Intent.
Intent有多个构造函数重载,但是我们现在只需要尝试启动另一个活动即可,所以现在我们来看其中之一的构造函数重载:Intent(Context pakageContext, Class<?> cls)
. 该构造函数接受两个参数,第一个就是当前所在的活动上下文,第二个参数则为目标活动的类。当准备好这些后,我们就可以通过startActivity()
来启动目标活动。
首先在上一节中的应用中创建一个新的活动,这次我们直接让Android Studio自动生成就好。
然后将上次缩写的Button onClick()改为:
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Intent intent = new Intent(FirstActivity.this, SecondActivity.class);
startActivity(intent);
}
});
以这种方式启动活动,我们称之为显示Intent.
然后我们来看看隐式Intent是如何使用的。
如果想使用隐式Intent启动另一个活动,需要指定目标活动的<action>
以及<category>
的android:name
.
我们可以看看Intent()的另外的构造方法:
Intent(Stirng action)
这个构造方法只需要传入一个参数,即为<action>
标签的android:name
首先,我们需要在清单文件中为第二个Activity加入<intent-filter>
并插入如下代码:
<intent-filter>
<action android:name="woodyman.com.activitytest.TEST"/>
<category android:name="android.intent.category.DEFAULT"/>
</intent-filter>
<action>
中通过加入包名+你想要的名称
即可,而<catagory>
中的DEFAULT指的是当我们使用隐式Intent没有指定category时,就从默认标签中寻找,当然,这个我们也是可以自己单独写的和上述为<action>
中的名称格式相同。
然后我们将FirstActivity中的onClick()稍作修改:
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Intent intent = new Intent("woodyman.com.activitytest.TEST");
startActivity(intent);
}
});
这里没有为intent选定category,原因就是上面所说的。如果我们是自己自定义的category,那么可以使用addCategory(String category)
来为intent插入我们自定义的category,同样可以达到上述的效果。但是,如果为intent加入了一个不存在的category,那么程序就会非正常退出,并给出错误信息:
android.content.ActivityNotFoundException: No Activity found to handle Intent { act=woodyman.com.activitytest.TEST cat=[woodyman.com.activitytest.MY_CATEGORY] }
我们只需要加上这个category就可以正常运行了,在上面的<intent-filter>
中插入代码:<category android:name="woodyman.com.activitytest.TEST"/>
即可。
当然,Intent也可以用来使用系统自带的应用,例如电话簿,拨号,相机等,个别权限需要在清单文件申请使用权限,即在<manifest>
下插入:<uses-permission android:name="权限名称"/>
,如果是个别敏感权限,不仅要在清单文件中申请,还要在调用相关代码前动态申请权限,才能够正常使用,具体有哪些权限可以参考后面的链接。而在代码中如果要申请使用权限,可以在Intent下找到相关的字符串常量,直接可以作为参数传入Intent(),
其中有些权限在书中也有提到并做了相关的举例:
需要打开一个网页,我们可以为Intent()传入Intent.ACTION_VIEW
然后为其加入我们想要打开的网页并转变为Uri,我们使用Uri.parse(),如下所示输入代码:
intent.setData(Uri.parse("https://www.baidu.com"))
或者也可以使用Intent(String action, Uri uri)
,在第二个参数传入我们想要打开的网页并将其解析转为Uri对象即可,如下所示:
Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse("https://www.baidu.com"));
后面的几个例子也是同理。
当我们为intent传入不同协议的的数据的时候,只有在<intent-filter>
中拥有相同协议的活动才能够响应:
我们如果需要制作有特定功能的活动(比如上面所讲的打开网页这一目的),我们需要在清单文件中,为该活动的<intent-filter>
插入相关的<data>
,具体有如下几类:
android:scheme. 用来制定协议的协议部分,如http, https, tel等。
android:host. 用来制定数据的主机名部分。
android:port. 用来指定数据的端口。
android:path. 用来指定端口后具体的路径部分.
android.mimeType. 用来指定可以处理的数据类型,可以使用通配符的方式进行指定。
组合在一起的uri格式为:<scheme>://<host>:<port>[<path>|<pathPrefix>|<pathPattern>]
- 活动之间的数据传递
当我们需要从活动A想活动B传输数据的时候,同样可以使用Intent来实现,只要使用putExtra(String name, XX data)
以及getXXExtra(String name)
就可以实现数据的存取。intent中,数据是以键值对的方式保存的:
putExtra(String name, XX data)
中,第一个参数name就是键,而第二个参数就是值,可以是多种类型。
getXXExtra(String name)
中,仅接受键就可以返回相应的值,但是返回对应的值需要对应名称的方法。
如果当B处理完并想将相关的数据返还给A,那么我们需要在A中将startActivity()
改为startActivityForResult()
,两方法目的都是相同的,只是在后这需要多输入一个参数,请求码。
startActivityForResult(Intent intent, int requestCode)
中,第一个参数为intent,第二个参数为请求码,用于确定发出该信息的来源。
然后在B中将需要返回的数据放入intent中,并作为setResult()
的参数即可:
setResult(int resultCode, Intent data)
,第一个参数为结果码,在书中所讲是用来返回处理结果的,一般只使用RESULT_OK
或RESULT_CANCELED
,第二个参数为待返回数据的intent.
之后可以在A中调用onActivityResult(int requestCode, int resultCode, Intent data)
方法,来处理返回的数据,通过第一个参数和第二个参数,我们可以确定该数据是的来源以及结果是否正确,第三个参数就是我们需要的数据了。
当然结果码如果是由自己确定的,也可以用来判定返回于哪一个组件或者活动的。
参考文章:
Android权限详细列表
Android Developer: data标签
请求码(requestCode)与结果码(resultCode)解析
上一节内容:第一行代码学习笔记——活动 Activity(二)
下一节内容:第一行代码笔记——活动的生命周期(四)