Android移动应用开发教程⑧

  • 本文为第八篇,本篇主要详细介绍述Intent的用途和组成部分,以及显式Intent和隐式 Intent的区别;接着阐述结合Intent和Bundle向下一个活动页面发送数据,再在下一个页面中解析收到的请求数据;然后叙述从下一个活动页面返回应答数据给上一个页面,并由上一个页面解析返回的应答数据。
  • 本文是对B站教程动脑学院 Android教程学习过程中所做的笔记!
  • 本文大部分为从视频中选取的知识点,其中有文字和小部分图片是由我自己编写的。
  • 本文承接上一篇文章《Android移动应用开发教程⑦》
  • 下一篇文章《Android移动应用开发教程⑨》

在活动之间传递消息

在活动之间传递消息最重要的类型就是intent,下面我们将详细介绍述Intent的用途和组成部分,以及显式Intent和隐式 Intent的区别;接着阐述结合Intent和Bundle向下一个活动页面发送数据,再在下一个页面中解析收到的请求数据;然后叙述从下一个活动页面返回应答数据给上一个页面,并由上一个页面解析返回的应答数据。

一:显式Intent和隐式Intent

Intent的中文名是意图,简单地说,就是传递消息。Intent是各个组件之间信息沟通的桥梁, 既能在Activity之间沟通,又能在Activity与Service之间沟通,也能在Activity与Broadcast之间沟通。总 而言之,Intent用于Android各组件之间的通信,它主要完成下列3部分工作:

  1. 标明本次通信请求从哪里来、到哪里去、要怎么走。
  2. 发起方携带本次通信需要的数据内容,接收方从收到的意图中解析数据。
  3. 发起方若想判断接收方的处理结果,意图就要负责让接收方传回应答的数据内容。

intent的组成元素如下:

指定意图对象的目标有两种表达方式,一种是显式Intent,另一种是隐式Intent。

1.1:显式Intent

显式Intent直接指定来源活动与目标活动,属于精确匹配。

在构建一个意图对象时,需要指定两个参数,第一个参数表示跳转的来源页面,即“来源 Activity.this”; 第二个参数表示待跳转的页面,即“目标Activity.class”。具体的意图构建方式有如下3种:

1.在Intent的构造函数中指定,示例代码如下:

Intent intent = new Intent(this, ActNextActivity.class); // 创建一个目标确定的意图

2.调用意图对象的setClass方法指定,示例代码如下:

Intent intent = new Intent(); // 创建一个新意图
intent.setClass(this, ActNextActivity.class); // 设置意图要跳转的目标活动

3.调用意图对象的setComponent方法指定,示例代码如下:

Intent intent = new Intent(); // 创建一个新意图
// 创建包含目标活动在内的组件名称对象
ComponentName component = new ComponentName(this, ActNextActivity.class);
intent.setComponent(component); // 设置意图携带的组件信息

 1.2:隐式Intent

隐式Intent,没有明确指定要跳转的目标活动,只给出一个动作字符串让系统自动匹配,属于模糊 匹配。

通常App不希望向外部暴露活动名称,只给出一个事先定义好的标记串,这样大家约定俗成、按图索骥 就好,隐式Intent便起到了标记过滤作用。这个动作名称标记串,可以是自己定义的动作,也可以是已 有的系统动作。

常见系统动作的取值说明见表:

动作名称既可以通过setAction方法指定,也可以通过构造函数Intent(String action)直接生成意图对象。 当然,由于动作是模糊匹配,因此有时需要更详细的路径。

Uri和Category便是这样的路径信息,Uri数据可通过构造函数Intent(String action, Uri uri)在生成对象时一起指定,也可 通过setData方法指定(setData这个名字有歧义,实际相当于setUri;Category可通过addCategory 方法指定,之所以用add而不用set方法,是因为一个意图允许设置多个Category,方便一起过滤。

String phoneNo = "12345";
Intent intent = new Intent(); // 创建一个新意图
intent.setAction(Intent.ACTION_DIAL); // 设置意图动作为准备拨号
Uri uri = Uri.parse("tel:" + phoneNo); // 声明一个拨号的Uri
intent.setData(uri); // 设置意图前往的路径
startActivity(intent); // 启动意图通往的活动页面

// 验证是否有activity处理该Intent
if (sendIntent.resolveActivity(getPackageManager()) != null) {
    startActivity(sendIntent);
}

调用 startActivity() 时,系统将检查已安装的所有应用,确定哪些应用能够处理这种 Intent(即:含 ACTION_SEND 操作并携带"text/plain"数据的 Intent )。 如果只有一个应用能够处理,则该应用将立即打开并为其提供 Intent。 如果多个 Activity 接受 Intent,则系统将显示一个对话框,使用户能够选取要使用的应用。

 隐式Intent还用到了过滤器的概念,把不符合匹配条件的过滤掉,剩下符合条件的按照优先顺序调用。 譬如创建一个App模块,AndroidManifest.xml里的intent-filter就是配置文件中的过滤器。像最常见的 首页活动MainAcitivity,它的activity节点下面便设置了action和category的过滤条件。其中 android.intent.action.MAIN表示App的入口动作,而android.intent.category.LAUNCHER表示在桌面 上显示App图标,配置样例如下:

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

二:向Activity发送数据和返回数据

2.1向下一个Activity发送数据

上一小节提到,Intent对象的setData方法只指定到达目标的路径,并非本次通信所携带的参数信息,真正的参数信息存放在Extras中。Intent重载了很多种putExtra方法传递各种类型的参数,包括整型、双精度型、字符串等基本数据类型,甚至Serializable这样的序列化结构。

只是调用putExtra方法显然不好 管理,像送快递一样大小包裹随便扔,不但找起来不方便,丢了也难以知道。

所以Android引入了 Bundle概念,可以把Bundle理解为超市的寄包柜或快递收件柜,大小包裹由Bundle统一存取,方便又 安全。 Bundle内部用于存放消息的数据结构是Map映射,既可添加或删除元素,还可判断元素是否存在。开发者若要把Bundle数据全部打包好,只需调用一次意图对象的putExtras方法;若要把Bundle数据全部取 出来,也只需调用一次意图对象的getExtras方法。Bundle对象操作各类型数据的读写方法说明见表

 接下来举个在活动之间传递数据的例子,首先在上一个活动使用包裹封装好数据,把包裹塞给意图对 象,再调用startActivity方法跳到意图指定的目标活动。完整的活动跳转代码示例如下:

// 创建一个意图对象,准备跳到指定的活动页面
Intent intent = new Intent(this, ActReceiveActivity.class);
Bundle bundle = new Bundle(); // 创建一个新包裹
// 往包裹存入名为request_time的字符串
bundle.putString("request_time", DateUtil.getNowTime());
// 往包裹存入名为request_content的字符串
bundle.putString("request_content", tv_send.getText().toString());
intent.putExtras(bundle); // 把快递包裹塞给意图
startActivity(intent); // 跳转到意图指定的活动页面

然后在下一个活动中获取意图携带的快递包裹,从包裹取出各参数信息,并将传来的数据显示到文本视图。下面便是目标活动获取并展示包裹数据的代码例子:

// 从布局文件中获取名为tv_receive的文本视图
TextView tv_receive = findViewById(R.id.tv_receive);
// 从上一个页面传来的意图中获取快递包裹
Bundle bundle = getIntent().getExtras();
// 从包裹中取出名为request_time的字符串
String request_time = bundle.getString("request_time");
// 从包裹中取出名为request_content的字符串
String request_content = bundle.getString("request_content");
String desc = String.format("收到请求消息:\n请求时间为%s\n请求内容为%s",
request_time, request_content);
tv_receive.setText(desc); // 把请求消息的详情显示在文本视图上

2.2:向上一个Activity返回数据

数据传递经常是相互的,上一个页面不但把请求数据发送到下一个页面,有时候还要处理下一个页面的 应答数据,所谓应答发生在下一个页面返回到上一个页面之际。如果只把请求数据发送到下一个页面, 上一个页面调用startActivity方法即可;如果还要处理下一个页面的应答数据,此时就得分多步处理,详细步骤说明如下:

步骤一,上一个页面打包好请求数据,调用startActivityForResult方法执行跳转动作,表示需要处理下 一个页面的应答数据,该方法的第二个参数表示请求代码,它用于标识每个跳转的唯一性。跳转代码示例如下:

String request = "你吃饭了吗?来我家吃吧";
// 创建一个意图对象,准备跳到指定的活动页面
Intent intent = new Intent(this, ActResponseActivity.class);
Bundle bundle = new Bundle(); // 创建一个新包裹
// 往包裹存入名为request_time的字符串
bundle.putString("request_time", DateUtil.getNowTime());
// 往包裹存入名为request_content的字符串
bundle.putString("request_content", request);
intent.putExtras(bundle); // 把快递包裹塞给意图
// 期望接收下个页面的返回数据。第二个参数为本次请求代码
startActivityForResult(intent, 0);

步骤二,下一个页面接收并解析请求数据,进行相应处理。接收代码示例如下:

// 从上一个页面传来的意图中获取快递包裹
Bundle bundle = getIntent().getExtras();
// 从包裹中取出名为request_time的字符串
String request_time = bundle.getString("request_time");
// 从包裹中取出名为request_content的字符串
String request_content = bundle.getString("request_content");
String desc = String.format("收到请求消息:\n请求时间为%s\n请求内容为%s",
request_time, request_content);
tv_request.setText(desc); // 把请求消息的详情显示在文本视图上

步骤三,下一个页面在返回上一个页面时,打包应答数据并调用setResult方法返回数据包裹。setResult 方法的第一个参数表示应答代码(成功还是失败),第二个参数为携带包裹的意图对象。返回代码示例如下:

String response = "我吃过了,还是你来我家吃";
Intent intent = new Intent(); // 创建一个新意图
Bundle bundle = new Bundle(); // 创建一个新包裹
// 往包裹存入名为response_time的字符串
bundle.putString("response_time", DateUtil.getNowTime());
// 往包裹存入名为response_content的字符串
bundle.putString("response_content", response);
intent.putExtras(bundle); // 把快递包裹塞给意图
// 携带意图返回上一个页面。RESULT_OK表示处理成功
setResult(Activity.RESULT_OK, intent);
finish(); // 结束当前的活动页面

步骤四,上一个页面重写方法onActivityResult,该方法的输入参数包含请求代码和结果代码,其中请求代码用于判断这次返回对应哪个跳转,结果代码用于判断下一个页面是否处理成功。如果下一个页面处理成功,再对返回数据解包操作,处理返回数据的代码示例如下:

// 从下一个页面携带参数返回当前页面时触发。其中requestCode为请求代码,
// resultCode为结果代码,intent为下一个页面返回的意图对象
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent intent)
{ // 接收返回数据
super.onActivityResult(requestCode, resultCode, intent);
// 意图非空,且请求代码为之前传的0,结果代码也为成功
if (intent!=null && requestCode==0 && resultCode== Activity.RESULT_OK) {
Bundle bundle = intent.getExtras(); // 从返回的意图中获取快递包裹
// 从包裹中取出名叫response_time的字符串
String response_time = bundle.getString("response_time");
// 从包裹中取出名叫response_content的字符串
String response_content = bundle.getString("response_content");
String desc = String.format("收到返回消息:\n应答时间为:%s\n应答内容为:%s",
response_time, response_content);
tv_response.setText(desc); // 把返回消息的详情显示在文本视图上
}
}

猜你喜欢

转载自blog.csdn.net/qq_64618483/article/details/129936232