使用Intent在活动之间穿梭

文章目录

使用Intent在活动之间穿梭

Intent是Android程序中各组件之间进行交互的一种重要方式,它不仅可以指明当前组件想要执行的动作,还可以在不同组件之间传递数据Intent一般可被用于启动活动、启动服务以及发送广播等场景,由于服务、广播等概念你暂时还未涉及,那么本章我们的目光无疑就锁定在了启动活动上面。

Intent大致可以分为两种:显式Intent 和隐式Intent,我们先来看一下显式Intent如何使用。

使用显式Intent

Intent有多个构造函数的重载,其中一个是Intent(Context packageContext, Class<?> cls) 。这个构造函数接收两个参数第一个参数 Context要求提供一个启动活动的上下文,第二个参数Class则是指定想要启动的目标活动 ,通过这个构造函数就可以构建出Intent的"意图"。然后我们应该怎么使用这个Intent呢?Activity类中提供了一个startActivity()方法,这个方法是专门用于启动活动的,它接收一个Intent参数,这里我们将构建好的Intent传入startActivity()方法就可以启动目标活动了。修改FirstActivity中按钮的点击事件,代码如下所示:

java 复制代码
button1.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent(FirstActivity.this, SecondActivity.class);
startActivity(intent);
}
});

我们首先构建出了一个Intent,传入FirstActivity.this作为上下文,传入SecondActivity.class作为目标活动,这样我们的"意图"就非常明显了,即在

FirstActivity这个活动的基础上打开SecondActivity这个活动。然后通过startActivity()方法来执行这个Intent。

使用这种方式来启动活动,Intent的"意图"非常明显 ,因此我们称之为显式Intent

使用隐式Intent

相比于显式Intent,隐式Intent则含蓄了许多,它并不明确指出我们想要启动哪一个活动,而是指定了一系列更为抽象的action和category等信息,然后交由系统去分析这个Intent,并帮我们找出合适的活动去启动。

什么叫作合适的活动呢?简单来说就是可以响应我们这个隐式Intent的活动,那么目前SecondActivity可以响应什么样的隐式Intent呢?额,现在好像还什么都响应不了,不过很快就会有了。

通过在<activity>标签下配置<intent-filter>的内容,可以指定当前活动能够响应的action和category,打开AndroidManifest.xml,添加如下代码:

java 复制代码
<activity android:name=".SecondActivity" >
<intent-filter>
<action android:name="com.example.activitytest.ACTION_START" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>

在<action>标签中我们指明了当前活动可以响应com.example.activitytest.ACTION_START这个action,而<category>标签则包含

了一些附加信息,更精确地指明了当前的活动能够响应的Intent中还可能带有的category。只有<action>和<category>中的内容同时能够匹配上Intent中指定的action和category时,这个活动才能响应该Intent。

修改FirstActivity中按钮的点击事件,代码如下所示:

java 复制代码
button1.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent("com.example.activitytest.ACTION_START");
startActivity(intent);
}
});

可以看到,我们使用了Intent的另一个构造函数,直接将action的字符串传了进去,表明我们想要启动能够响应com.example.activitytest.ACTION_START这个action的活动。那前面不是说要<action>和<category>同时匹配上才能响应的吗?怎么没看到哪里有指定category呢?这是因为android.intent.category.DEFAULT是一种默认的category,在调用startActivity()方法的时候会自动将这个category添加到Intent中。重新运行程序,在FirstActivity的界面点击一下按钮,你同样成功启动SecondActivity了。不同的是,这次你是使用了隐式Intent的方式来启动的,说明我们在<activity>标签下配置的action和category的内容已经生效了!

每个Intent中只能指定一个action,但却能指定多个category。目前我们的Intent中只有一个默认的category,那么现在再来增加一个吧。

修改FirstActivity中按钮的点击事件,代码如下所示:

java 复制代码
button1.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent("com.example.activitytest.ACTION_START");
intent.addCategory("com.example.activitytest.MY_CATEGORY");
startActivity(intent);
}
});

可以调用Intent中的addCategory()方法来添加一个category,这里我们指定了一个自定义的category,值为com.example.activitytest.MY_CATEGORY。

现在重新运行程序,在FirstActivity的界面点击一下按钮,你会发现,**程序崩溃了!**这是你第一次遇到程序崩溃,可能会有些束手无策。别紧张,其实大多数的崩溃问题都是很好解决的,只要你善于分析。在logcat界面查看错误日志,你会看到如图所示的错误信息:

错误信息中提醒我们,没有任何一个活动可以响应我们的Intent,为什么呢?这是因为我们刚刚在Intent中新增了一个category,而SecondActivity的<intent-filter>标签中并没有声明可以响应这个category,所以就出现了没有任何活动可以响应该Intent的情况。现在我们在<intent-filter>中再添加一个category的声明,如下所示:

java 复制代码
<activity android:name=".SecondActivity" >
<intent-filter>
<action android:name="com.example.activitytest.ACTION_START" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="com.example.activitytest.MY_CATEGORY"/>
</intent-filter>
</activity>

再次重新运行程序,你就会发现一切都正常了。

更多隐式Intent的用法

掌握了通过隐式Intent来启动活动的方法,但实际上隐式Intent还有更多的内容需要你去了解,本节我们就来展开介绍一下。使用隐式Intent,我们不仅可以启动自己程序内的活动,还可以启动其他程序的活动,这使得Android多个应用程序之间的功能共享成为了可能。比如说你的应用程序中需要展示一个网页,这时你没有必要自己去实现一个浏览器(事实上也不太可能),而是只需要调用系统的浏览器来打开这个网页就行了。

修改FirstActivity中按钮点击事件的代码,如下所示:

java 复制代码
button1.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setData(Uri.parse("http://www.baidu.com"));
startActivity(intent);
}
});

这里我们首先指定了Intent的action是Intent.ACTION_VIEW,这是一个Android系统内置的动作,其常量值为android.intent.action.VIEW。然后通过Uri.parse()方法,将一个网址字符串解析成一个Uri对象,再调用Intent的setData()方法将这个Uri对象传递进去

重新运行程序,在FirstActivity界面点击按钮就可以看到打开了系统浏览器,如图所示:

在上述代码中,可能你会对setData()部分感觉到陌生,这是我们前面没有讲到的。这个方法其实并不复杂,它接收一个Uri对象,主要用于指定当前Intent正在操作的数据,而这些数据通常都是以字符串的形式传入到Uri.parse()方法中解析产生的。与此对应,我们还可以在<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了。

为了让你能够更加直观地理解,我们来自己建立一个活动,让它也能响应打开网页的Intent。

右击com.example.activitytest包→New→Activity→Empty Activity,新建ThirdActivity,并勾选Generate Layout File,给布局文件起名为third_layout,点击Finish完成创建。然后编辑third_layout.xml,将里面的代码替换成如下内容:

xml-dtd 复制代码
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<Button
android:id="@+id/button_3"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Button 3"
/>
</LinearLayout>

ThirdActivity中的代码保持不变就可以了,最后在AndroidManifest.xml中修改ThirdActivity的注册信息:

java 复制代码
<activity android:name=".ThirdActivity">
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<data android:scheme="http" />
</intent-filter>
</activity>

我们在ThirdActivity的<intent-filter>中配置了当前活动能够响应的action

是Intent.ACTION_VIEW的常量值,而category则毫无疑问指定了默认的category值,另外在<data>标签中我们通过android:scheme指定了数据的协议必须是http协议,这样ThirdActivity应该就和浏览器一样,能够响应一个打开网页的Intent了。让我们运行一下程序试试吧,在FirstActivity的界面点击一下按钮,结果如图所示:

可以看到,系统自动弹出了一个列表,显示了目前能够响应这个Intent的所有程序。选择Browser还会像之前一样打开浏览器,并显示百度的主页,而如果选择了ActivityTest,则会启动ThirdActivity。JUST ONCE表示只是这次使用选择的程序打开,ALWAYS则表示以后一直都使用这次选择的程序打开。需要注意的是,虽然我们声明了ThirdActivity是可以响应打开网页的Intent的,但实际上这个活动并没有加载并显示网页的功能,所以在真正的项目中尽量不要出现这种有可能误导用户的行为,不然会让用户对我们的应用产生负面的印象。

除了http协议外,我们还可以指定很多其他协议,比如geo表示显示地理位置、tel表示拨打电话。下面的代码展示了如何在我们的程序中调用系统拨号界面。

java 复制代码
button1.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent(Intent.ACTION_DIAL);
intent.setData(Uri.parse("tel:10086"));
startActivity(intent);
}
});

首先指定了Intent的action是Intent.ACTION_DIAL,这又是一个Android系统的内置动作。然后在data部分指定了协议是tel,号码是10086。重新运行一下程序,在FirstActivity的界面点击一下按钮,结果如图所示:

如果对你有帮助,就一键三连呗(点赞+收藏+关注),我会持续更新更多干货~~

相关推荐
千里马学框架16 小时前
一起学 Android 14:ShellTransition 屏幕旋转过程深度剖析
android·智能手机·性能优化·framework·性能·屏幕旋转·rotation
美狐美颜SDK开放平台16 小时前
开发直播APP时如何接入视频美颜SDK?开发流程与注意事项
android·人工智能·计算机视觉·音视频·直播美颜sdk
AFinalStone16 小时前
Android7 SystemUI源码解析(七)Keyguard锁屏模块深度解析
android·systemui
致远ccc17 小时前
Google Play 上架前如何测试 App?多国家 Android 环境测试
android·app测试·googleplay·多国家应用测试
ttyyttemo19 小时前
Kotlin 协程中的 Job 结构化并发与取消
android
sun00770019 小时前
tbox 4g/5g切换,导致wan ip 改变,导致车机旧网络不可用。需要重启车机才行
android
其实防守也摸鱼20 小时前
内网穿透与反向代理:原理、工具与实战指南
android·大数据·运维·安全·网络安全·自动化·渗透
AFinalStone21 小时前
Android7 SystemUI 源码解析(四)NavigationBar 导航栏与 SystemBars
android·systemui
JMchen21 小时前
属性动画原理与高级动画实现
android·kotlin·canvas
AFinalStone21 小时前
Android7 SystemUI 源码解析(二)启动流程深度解析
android·systemui