1. 使用Intent
- 在03 - Activity的基本用法的项目基础上, 新增一个Empty Activity, 命名为SecondActivity, 并且勾选Generate Layout File(系统为这个活动创建出一个布局文件), 但是不要选中, Launcher Activity, 这样程序的启动活动还是MainActivity;
- 过程及创建结果如下:
1.1 布局文件
- 打开activity_second.xml布局文件, 可以看到系统已经自动帮我们创建了内容, 但是比较复杂,就改成熟悉的LinearLayout根布局, 再加一个Button, 代码如下:
- activity_second.xml:
1.2 SecondActivity.java
- 活动中的代码, 系统也做好了初始化
1.3 AndroidManifest.xml清单文件
- 清单文件同样做好了初始化
1.4 如何启动SecondActivity活动——intent
- 由于SecondActivity不是主活动, 所以不需要配置
<intent-filter>
标签里面的内容, 接下来就是引入intent去启动第二个活动; intent
是Android程序中各组件(前面介绍过四大组件)之间进行交互的一种重要的方式, 它不仅可以指明当前组件想要执行的动作, 还可以在不同组件之间传递数据。Intent一般可被用于启动活动、启动服务以及发送广播等场景。
1.4.1 显示Intent如何使用?
-
intent有多个构造函数的重载, 其中一个是
Intent(Context packageContext, Class<?> cls)
。 -
这个构造函数会接收两个参数, 第一个参数Context:提供一个启动活动的上下文(环境); 第二个参数Class:指定想要启动的目标活动。 通过这个构造函数就可以构建出Intent的“意图”, 然后通过Activity类中提供的startActivity()方法, 将意图Intent传入, 即可启动活动;
-
代码如下:(点击第一个活动(MainActivity)的按钮就会启动SecondActivity活动)
-
先构建一个Intent, 将MainActivity.this传入作为上下文, 将SecondActivity.class作为目标活动,这样就创建出一个非常明显的意图, 即在MainActivity这个活动的基础上打开SecondActivity活动。通过startActivity()方法来执行这个Intent;
-
当打开第二个活动后, 按下Back键就可以销毁当前的活动, 从而回到上一个活动中;
-
因为这样的方式, 意图非常明显, 所以称之为显示Intent
1.4.2 隐式Intent如何使用?
- 隐式Intent并不明确指出我们想要启动哪一个活动, 而是指定了一系列更为抽象的action和category等信息, 然后交由系统去分析这个Intent, 并帮我们找出合适的活动去启动。
- 所谓合适的活动就是指可以响应我们这个隐式Intent的活动, 响应,这里之前没有过概念可能理解不了, 等看完下面的实例就能明白了。
1. 实例操作
- 在清单文件(SecondActivity)
<activity>
标签下配置<intent-filter>
的内容, 可以指定SecondActivity活动可以响应的action和category, 添加如下代码:
- 在
<action>
标签中, 我们指明了**当前活动(SecondActivity)**可以响应com.example.firsttest.ACTION_START
(自定义的)这个action; <category>
标签则包含了一些附加的信息, 更精确地指明了当前的活动能够响应的Intent中还可能带有的category。只有<action>
和<category>
中的内容能同时匹配上在Intent中指定的action和category时, 这个活动才能响应此activity(SecondActivity);- 如果是implicit intent(隐式Intent),android默认给加上一个CATEGORY_DEFAULT,这样的话如果
intent filter
中没有android.intent.category.DEFAULT
这个category的话,匹配测试就会失败。所以,如果你的 activity支持接收implicit intent的话就一定要在intent filter中加入android.intent.category.DEFAULT。
- MainActivity中的逻辑代码:
- 可以看到, 这里使用了Intent的另一个构造函数, 直接将action的字符串传了进来, 表明, 我们想要启动能够响应com.example.firsttest.ACTION_START这个action的活动(activity);
- 可以看到, 前面的AndroidManifest.xml中, 我们配置了SecondActivity能够响应的action和category, 而代码中只有action的配置, 并且前面说过, 代码要将
<action>
和<category>
同时匹配上才能响应, 但是将程序运行后, SecondActivity仍然可以完成响应启动, 为什么呢?- 因为
android.intent.category.DEFAULT
是一种默认的category, 在调用startActivity()
方法的时候, 会自动将这个category添加到Intent中。
- 因为
2. 每个Intent中可以指定多个category, 但只能指定一个action
- 操作:在AndroidManifest.xml中新增一个category, 且在代码中调用addCategory方法添加一个category, 效果和上面的一样;
1.4.3 更多隐式Intent的用法
- 使用隐式Intent, 不仅可以启动自己程序内的活动, 还可以启动其他程序的活动, 这使得Android多个应用程序之间的功能共享成为了可能。
- 例如, 在你开发的应用程序内要展示一个网页, 你没有必要去自己开发一个浏览器, 而是只需要调用系统的浏览器来打开这个网页即可。
1. 演示:在你开发的应用程序内打开百度网页
-
过程:点击按钮, 打开网页百度
-
代码中, 先指定了Intent的action是
Intent.ACTION_VIEW
, 这是一个Android系统内置的动作, 其常量值为android.intent.action.VIEW
;Intent.ACTION_VIEW
用于显示用户的数据,比较通用,会根据用户的数据类型打开相应的Activity(活动); -
通过【统一资源标识符(Uniform Resource Identifier,URI)】
Uri.parse()
方法, 将一个网址字符串解析成一个Uri对象, 再调用Intent的setData()
方法将这个Uri对象传进去; -
setData()
方法:接收一个Uri对象, 主要用于指定当前Intent正在操作的数据, 而这些数据通常是以字符串的形式, 经过Uri.parse()
的解析产生的;
2. <intent-filter>
中配置<data>
标签
- 可以在
<intent-filter>
中再配置一个<data>
标签, 用于更精确地指定当前活动能够响应什么类型的数据 <data>
标签中主要可以配置以下内容- android:scheme。用于指定数据的协议部分, 如上例中的http部分;
- android:host。用于指定数据的主机部分, 如上例中的www.baidu.com部分;
- android:port。用于指定数据的端口部分, 一般紧随在主机名之后;
- android:path。用于主机名和端口之后的部分, 如一段网址中跟在域名之后的内容;
- android:mimeType。用于指定可以处理的数据类型, 允许使用通配符的方式进行指定;
- 只有
<data>
标签中指定的内容和Intent中携带的Data完全一致时, 当前活动才能够响应此Intent。不过一般在<data>
标签中都不会指定过多的内容, 比如上面那个例子, 只要指定android:scheme为http, 就可以响应所有的http协议的Intent。
(1)实例操作
-
在这个项目的包下, 新建一个Empty Activity —— ThirdActivity, 并且创建的时候记得√Generate Layout File, 为这个活动创建一个布局文件, 在这个布局文件中添加一个按钮Button;
-
MainActivity中的代码不变:
-
接着在AndroidManifest.xml清单文件中配置注册信息, 代码如下:
- 在ThirdActivity的
<intent-filter>
中配置了当前活动(ThirdActivity)能够响应的action是android.intent.action.VIEW
(即Intent.ACTION_VIEW
)的常量值, 而category指定了默认的category值, 在<data>
标签中通过android:scheme指定了数据的协议必须是http协议, 这样ThirdActivity就和浏览器一样, 能够响应一个要打开网页的Intent;
- 在ThirdActivity的
- 启动程序后, 在MainActivity活动中点击按钮:
- 可以看到在演示中, 系统自动弹出了一个列表, 显示了目前能够响应这个Intent的所有程序;选择Chrome就会像之前的例子中,通过浏览器打开百度的网页;而选择firstTest, 就会启动ThirdActivity活动 , 可以看到**“第三按钮”;**
- JUST ONCE:仅这次使用选择的程序打开;
- ALWAYS: 总是使用这次选择的程序打开;
- 虽然, 可以通过声明让ThirdActivity活动能响应打开网页的Intent, 但是这个活动它实际上是不具备浏览器内核的功能, 所以实际开发尽量不要出现这样的行为, 否则会对使用者产生一个误导;
(2) 补充
- 除了http协议外, 还可以指定很多其他的协议, 比如, geo:显示地理位置;tel:表示拨打电话;
- 下面展示一个在程序中调用系统拨号界面的例子:
- 先指定了Intent的action是Intent.ACTION_DIAL, 这也是一个Android系统的内置动作;
- 在data部分指定了协议是tel, 号码是10086;
- 可以看到在MainActivity活动的界面中点击按钮之后, 会跳转到系统的拨号界面;
2. 向下一个活动传递数据
2.1 介绍与实现
- 在Intent中提供了一系列
putExtra()
方法的重载, 可以把我们想要传递的数据暂存在Intent中, 启动另一个活动后, 只需要在另外一个活动中把这些数据再从Intent中取出来就可以了;
- 目标:在MainActivity中有一个字符串, 现在要讲这个字符串传递到SecondActivity中, 代码实现如下:(这里利用显示Intent的方法)
MainActivity.java:
putExtra()
方法, 这里接收两个参数, key键和value值, 可以用于后面从Intent中取值, value则是要传递的值;
SecondActivity.java:
- 用
getIntent()
方法获取到用于启动SecondActivity的Intent, 接着调用getStringExtra()
方法, 传入相应的键值key, 就可以获取到传递的数据了;接着再显示在SecondActivity的Button按钮上; - 因为这里传递的是String类型, 所以取的时候用的是
getStringExtra()
方法来获取传递的数据;如果传递的是整型的数据, 就可以用getIntExtra()
方法;
- 用
- 结果展示如下:
3. 返回数据给上一个活动
3.1 startActivityForResult()
方法
- 返回上一个活动只需要按一下Back键就行;
startActivityForResult()
方法也可以用来启动活动, 但是这个方法期望在活动销毁的时候能够返回一个结果给上一个活动;startActivityForResult()
方法接收两个参数, 参数1:Intent, 参数2:请求码;- 请求码:用于在之后的回调中判断数据的来源;【请求码一定要唯一值】
3.1.1 实践操作
MainActivity.java:
使用startActivityForResult()
方法启动SecondActivity, 请求码确保唯一值即可;
2. SecondActivity.java:
为按钮注册一个点击事件, 在点击事件中实现返回数据的逻辑代码
- 这里构建的一个Intent, 仅仅用来传递数据, 可以看到它也没有指定任何“意图”(无论显示, 隐式), 将想要传递(返回)的数据存在这个Intent中, 调用
setResult()
方法(这个方法专门用于向上一个活动返回数据); setResult()
方法接收两个参数, 参数1:用于向上一个活动返回处理的结果;参数2:将带有数据的Intent传递回去;- 接着调用
finish()
方法销毁当前活动(即可返回上一个活动);
- 因为使用
startActivityForResult()
方法来启动SecondActivity
, 在SecondActivity
被销毁之后就会回调上一个活动的onActivityResult()
方法, 所以要在MainActivity(上一个活动)中重写这个方法来得到返回来的数据;
onActivityResult()
方法带有三个参数:- 参数1, requestCode:在启动活动时传入的请求码;
- 参数2, resultCode:在返回数据时传入的处理结果 ;
- 参数3, Intent data:即携带着返回数据的Intent;
- 因为在一个活动中可能会调用很多个
startActivityForResult()
方法去启动很多不同的活动, 而每个活动返回的数据都会回调到onActivityResult()
方法中, 所以一定要先检查requestCode的值去判断返回数据的来源;确定后, 再通过resultCode的值来判断处理结果是不是成功的, 成功的话, 再把值从Intent中取出; - 代码如下: