想了解【Android】Android四大组件之Activity的新动态吗?本文将为您提供详细的信息,我们还将为您解答关于android的4大组件的相关问题,此外,我们还将为您介绍关于Android四
想了解【Android】Android四大组件之Activity的新动态吗?本文将为您提供详细的信息,我们还将为您解答关于android的4大组件的相关问题,此外,我们还将为您介绍关于Android 四大组件 (一) Activity 生命周期、Android 四大组件之 Activity、Android 四大组件之 Activity 解析(上)、Android 四大组件之 Activity 解析(下)的新知识。
本文目录一览:- 【Android】Android四大组件之Activity(android的4大组件)
- Android 四大组件 (一) Activity 生命周期
- Android 四大组件之 Activity
- Android 四大组件之 Activity 解析(上)
- Android 四大组件之 Activity 解析(下)
【Android】Android四大组件之Activity(android的4大组件)
Activity是与用户交互的接口。
Android系统是通过Activity栈的形式来管理Activity。
Activity的4种状态:Active / Paused / Stopped / Killed。
Activity是什么
Activity是Android的四大组件之一。是用户操作的可视化界面;它为用户提供了一个完成操作指令的窗口。当我们创建完毕Activity之后,需要调用setContentView()
方法来完成界面的显示;以此来为用户提供交互的入口。在Android App 中只要能看见的几乎都要依托于Activity,所以Activity是在开发中使用最频繁的一种组件。
Activity的生命周期
在Android中会维持一个Activity Stack(Activity栈),当一个新的Activity创建时,它就会放到栈顶,这个Activity就处于运行状态。当再有一个新的Activity被创建后,会重新压人栈顶,而之前的Activity则会在这个新的Activity底下,就像子弹被压入枪梭一样。而且之前的Activity就会进入后台。
一个Activity实质上有四种状态:
- 运行中(Running/Active):这时Activity位于栈顶,是可见的,并且可以用户交互。
- 暂停(Paused):当Activity失去焦点,不能跟用户交互了,但依然可见,就处于暂停状态。当一个新的非全屏的Activity或者一个透明的Activity放置在栈顶,Activity就处于暂停状态;这个时候Activity的各种数据还被保持着;只有在系统内存在极低的状态下,系统才会自动的去销毁Activity。
- 停止(Stoped):当一个Activity被另一个Activity完全覆盖,或者点击HOME键退入了后台,这时候Activity处于停止状态。这里有些是跟暂停状态相似的:这个时候Activity的各种数据还被保持着;当系统的别的地方需要用到内存时,系统会自动的去销毁Activity。
- 销毁(Detroyed):当我们点击返回键或者系统在内存不够用的情况下就会把Activity从栈里移除销毁,被系统回收,这时候,Activity处于销毁状态。
上面的四种状态稍微笼统的介绍了一下Activity在不同时期的状态,接下来通过具体的回调方法看一下Activity的生命周期,下面是官网提供的一张Activity在各个状态下回调用的回调方法:
在Activity运行之前,会通过onCreate(),onStart(),onResume();当运行完onResume()之后,Activity就处于上面说的Running/Active 状态了。
当Activity处于暂停状态时,会调用onPause(),这个时候Activity还是见的。当在这个时候Activity恢复到运行状态时,会重新调用onResume()。
当Activity处理停止状态时,会调用onStop(),这个时候如果要恢复到运行状态就会调用一个新的方法onRestart(),然后去调用onStart(),onResume()。
当Activity被销毁时,就会调用onDestroy(),那么如果要恢复Activity的显示就需要重新创建这个Activity;重新去走onCreate(),onStart(),onResume()这三个方法。
虽然通过字面意思可以大概了解这些方法的作用,但是我们还是需要说一下,它们的具体功能。
onCreate: 当Activity第一次被创建时调用。是生命周期开始的第一个方法。在这里我们可以做一些初始化的操作,比如:调用setContentView()方法去加载界面,绑定布局里的一些控件,初始化一些Activity需要用到的数据。之后会调用onStart方法.
onStart:当Activity正在变为可见时调用。这个时候Activity已经可见了,但是还没有出现在前台还不能跟用户交互。可以简单理解为Actvity已经可见但是还没有出现在前台。之后会调用onResume.
onResume:当Activity可以跟用户交互时调用,这个时候,这个Activity位于栈的顶部。跟onStart相比,它们都是表示Activity已经可见,但是onStart调用时Activity还在后台,而调用onResume时,Activity已经进入了前台,可以跟用户交互了。之后会调用 onPause.
onPause:当Activity暂停时调用这个方法;在这里我们可以用来保存数据,关闭动画和其它比较耗费cpu的操作;但是在这里做的操作绝对不能耗时,因为如果当前Activity要启动一个新的Activity,这个新的Activity会在当前Activity执行完毕onPause之后才能进入可见状态。这个方法之后一般会调用的方法有onStop或者onResume.
onStop:当Activity进入后台,并且不会被用户看到时调用。当别的Activity出现在前台时,或者Activity会被销毁时,调用此方法;在这个方法调用之后,系统可能会在内存不够的情况下回收Activity;在这个方法之后一般会调用onRestart或者onDestroy.
onDestroy:这个方法是Activity生命周期中调用的最后一个方法。它会在Activity被销毁之前调用;Activity销毁原因一般是我们调用Activity的finish方法手动销毁,另一个就是系统在内存紧张的情况下去销毁Activity,以用来节省空间。我们可以通过方法 isFinishing 来判断Activity是否正在被销毁。
onRestart:这个方法是在Activity处于停止状态后,又回到可视状态时调用。之后会调用onResume.
以上是Activity的生命周期方法,除此之外Activity还有两个方法感觉大家也应该知道,虽然它们不属于Activity的生命周期方法。这俩方法是:onSaveInstanceState 和 onRestoreInstanceState。,
onSaveInstanceState:
它不属于Activity的生命周期方法,不一定会被触发,但是当应用遇到意外情况,比如:内存紧张,用户点击了Home键或者用户按下电源键关闭屏幕等这些情况,这时系统可能会去销毁Activity,这时这个方法就会被调用。这里强调的是系统去回收Activity,而不是我们去手动的销毁Activity。这个方法提供了一个Bundle对象,我们可以通过它来保存一些临时性的状态或者数据。通常这个方法只适合保存临时数据,如果需要数据的持久化保存等操作,还是要在onPause方法里执行才好。当 Activity再次被创建时,Activity会通过onCreate(Bundle)或者onRestoreInstanceState(Bundle)执行的时候,会将提供一个的Bundle对象来恢复这些数据。
onRestoreInstanceState:
这个方法调用的前提是,Activity必须是被系统销毁了,在Activity被再次创建时它会在onStart()方法之后被调用。
下面总结一下Activity的生命周期:
正常情况下Activity的生命周期是:
onCreate->onStart->onResume->onPause->onStop->onDestroy
-
对于一个正常的Activity,第一次启动,会依次回调以下方法:
onCreate->onStart->onResume -
当我们打开一个新的Activity或者点击Home键回到桌面后,会依次回调以下方法:
onPause->onStop
上面提到过,如果新的Activity是透明的(采用的透明主题),当前的Activity不会回调onStop.
-
当我们再次回到原Activity,会依次回调以下方法:
onRestart->onStart->onResume -
当我们点击返回键后,会依次回调以下方法:
onPause->onStop->onDestroy. -
当Activity被系统回收后,再次被打开,会跟第一次启动的时回调生命周期方法一样(不包含 onSaveInstanceState 和 onRestoreInstanceState)。
-
我们可以注意到 其中onCreate 跟 onDestroy 是相对的。一个创建一个销毁。并且其只可能被调用一次。按照这种配对方式,我们也可以看出 onStart跟onStop 是配对的,这两个方法可以被多吃调用。onResume 和 onPause 也是配对的,它们一个获取焦点和用户交互,一个正好相反。
-
onStart和onResume,onPause和onStop,这两对方法在功描述差不多,那为什么还要重复存在呢?
其实这两对方法分别代表不同的意义,onStart和onStop 是Activity是否可见的标志,而onResume和onPause是从Activity是否位于前台的标志,它们针对的角度不同。 -
在onPause里不能做耗时操作,因为如果要启动一个新的Activity,新的Activity必须要在前一个Activity的onPause 方法执行完毕之后才会启动的新的Activity。
上面是正常情况下的生命周期方法调用,下面简单说一下异常情况下Activity的生命周期:
在系统内存不够时会根据优先级杀死Activity。怎么判断Activity的优先级呢?
- 最高的优先级:在前台显示并且跟用户交互的Activity,优先级最高,
- 暂停状态的Activity优先级次之:如果Activity没有在前台,但是可见,不可与用户交互,比如弹出一个对话框等。
- 处于后台Activity优先级最低:执行了onStop方法的Activity优先级最低。它不可见,并且无法跟用户交互。
当系统内存不足,就会按照优先级去销毁Activity,在销毁Activity时会额外的在onPause和onStop之间调用onSaveInstanceState;当要重新创建这个Activity 时,会在onStart方法之后调用onRestoreInstanceState方法。
Android 四大组件 (一) Activity 生命周期
简单粗暴。
分两块来熟悉activity生命周期:一.典型生命周期过程;二.异常情况下的生命周期过程。
一. 典型生命周期过程
Activitiy的生命周期方法主要有七个:onCreate()、onRestart()、onStart()、onResume()、onPause()、onStop()、onDestory()。
1. onCreate()
onCreate方法是整个生命周期中唯一必须实现的方法。布局都是在Activity中进行,在该方法中做一些初始化的操作,如通过setContentView设置界面布局的资源,初始化所需要的组件信息等。
2. onRestart()
当Activitiy被onStop()并且没有被killed时候,调用这个方法进行唤醒,也可以说理解为,当处于非栈顶状态的活动需要再次返回栈顶,展现给用户的时候,触发该方法。该方法优先于onStart()方法。
3.onStart()
表示Activity正在启动,但是无法与用户进行交互。可以把onStart和onStop看成一对。
4.onResume()
Activity已在前台可见,可与用户交互了。
onResume方法与onStart的相同点是两者都表示Activity可见,只不过onStart回调时Activity还是后台无法与用户交互,而onResume则已显示在前台,可与用户交互。
5.onPause()
这个方法之后有可能是onResume也有可能是onStop。用于提交未保存发生变化了的持久化数据,及停止动画及其他其他比较消耗CPU的事件,这是为了更好的运行新的activity。当在activity中打开的是一个dialog不完全覆盖这个activity,则activity就会是onPause状态。
6.onStop()
activity完全看不见的时候,会调用onStop方法。当用户自己退出程序的时候,建议在onStop方法中保存数据。此时Activity不可见,仅在后台运行。同样地,在onStop方法可以做一些资源释放的操作(不能太耗时)。
7.onDestroy()
Activity正在被销毁,也是生命周期最后一个执行的方法,一般我们可以在此方法中做一些回收工作和最终的资源释放。
二、异常情况下的生命周期过程
异常生命周期产生原因一般有这两种:
1.横竖屏切换;
Activity处于竖屏状态,如果突然旋转屏幕,由于系统配置发生了变化,在默认的情况下,Activity会被销毁并重新创建。
可以在onSaveInstanceState方法中存储一些数据以便Activity重建之后可以恢复这些数据。onSaveInstanceState和onRestoreInstanceState只有在Activity异常终止时才会被调用的,正常情况是不会调用这两个方法的。
当我们不想Activity在屏幕旋转后导致销毁重建时,可以设置configChange=“orientation”;当SDK版本大于13时,我们还需额外添加一个“screenSize”的值,对于这两个值含义如下:
orientation:屏幕方向发生变化,配置该参数可以解决横竖屏切换时,Activity重建问题(API<13)
screenSize:当设备旋转时,屏幕尺寸发生变化,API>13后必须配置该参数才可以保证横竖切换不会导致Activity重建。
设置了这两个参数后,当横竖屏切换时,Activity不会再重建并且也不会调用之前相关的方法,取而代之的是回调onConfigurationChanged方法.
2.内存不足的时候killed优先级低的activity.
android系统中进程优先级由高到低依次是:前台进程,可见进程、服务进程、后台进程、空进程.
Android 四大组件之 Activity
Activity,Android 四大組件之一,主要用于显示与用户交互的界面。
在开发中新建一个实现 Activity 的类时,会默认继承 AppCompatActivity,该类的继承关系如下:
AppCompatActivity <- FragmentActivity <- ComponentActivity <- Activity <- ContextThemeWrapper <- ContextWrapper <- Context
说明 Activity 类在之后被改动了多次。
Activity 的生命周期:
打开(onCreate,onStart,onResume),关闭或 kill(onPause,onStop,onDestroy)
切换到另外 Activity,桌面或其他 App(onPause,onStop),回到 Activity(onRestart,onStart,onResume)
旋转(onPause,onStop,onDestroy,onCreate,onStart,onResume,先关闭再打开)
弹出关闭 Dialog 周期不变,被系统 kill 周期函数也不会被调用
数据保存:在 Activity 中避免数据突然丢失时,可将临时数据保存在 onSaveInstanceState 方法中,在 onCreate 中取出,并通过 Bundle 来 put 数据。永久数据保存在 onPause 方法中。
Activity 有四种启动方式:
- standard
默认模式,以叠加的方式将 Activity 加入到栈中
- singleTop
对应要启动的 Activity 如果是在栈顶,那么不会新建,否则会重新创建一个 Activity
- singleTask
如果栈中存在对应的 Activity,则使用该 Activity,否则创建新的 Activity
- singleInstanst
启动 Activity 时会新建一个任务栈来存放,如果已经有相同的 Activity 存在,则会重用。
taskAffinity 可以指定 Activity 放在哪个栈 Task 中,默认是包名
Activity 在启动时也可以设置一些样式,如动画等
Activity 任务栈:每启动一个 App 就会新建一个任务栈,桌面 launch 本身也是一个任务栈,任务栈通过 id 和 taskAffinity 来标识
在开发中,通常会使用 Stack 来统一管理 Activity。
使用 startActivity (Intent) 可以实现 Activity 之间的跳转。
Android 四大组件之 Activity 解析(上)
segmentfault 对 mackdown 语法的支持不是很好,有些图片都显示不出来,大家可以去我的掘金查看这篇文章。
一、概述
<font face = "黑体">简单来讲,Activity 就是一个可视化界面,负责承建一个屏幕窗口,防止 UI 组件,供用户交互。一般来说承建 Activity 有三个步骤:
- <font face = "黑体">承建 Activity 类;
- <font face = "黑体">在 AndroidManifest.xml 中注册;
- <font face = "黑体">设置布局文件(可选)。
二、Activity 的启动方法
2.1、显示启动
<font face = "黑体">明确指定要启动的 Activity 的 $\color{red}{class}$ 或者 $\color{red}{包名.activity类名}$,显示启动主要有三种方式:
方式一:<font color = red>class 跳转(最常用)
Intent intent = new Intent(MainActivity.this, SecondActivity.class); startActivity(intent);
方式二:<font color = red>包名.类名 跳转
Intent intent = new Intent(); intent.setClassName(MainActivity.this, "com.zjgsu.activitydemo.SecondActivity"); startActivity(intent);
方式三:<font color = red>ComponentName 跳转
Intent intent = new Intent(); intent.setComponent(new ComponentName(MainActivity.this, SecondActivity.class)); startActivity(intent);
2.2、隐式启动
<font face = "黑体">设置启动过滤器,通过指定的 $\color{red}{action}$ 或 $\color{red}{action 和 data}$ 属性,系统会查找符合条件的 Activity,并启动它,隐私启动主要有两种方式:
方式一:<font color = red>传入 actionName
Intent intent = new Intent("abcd.SecondActivity"); startActivity(intent);
方式二:<font color = red>设置 action
Intent intent = new Intent(); intent.setAction("abcd.SecondActivity"); startActivity(intent);
<font face = "黑体" color = red>注意:如果自己定义的某个 Activity 要通过隐式启动,在 AndroidManifest.xml 中必须加上 android.intent.category.DEFAULT,否则不起作用。
<activity android:name=".SecondActivity">
<intent-filter>
<action android:name="abcd.SecondActivity"/>
<category android:name="android.intent.category.DEFAULT"/>
</intent-filter>
</activity>
2.2.1、隐式启动如果两个 activity 的 actionName是一样的会怎样呢?
<font face = "黑体">如下所示,我创建了两个 Activity,然后这两个 Activity 的 actionName 我设置成一样的,然后我通过隐式启动 Activity,会怎样呢?
<activity android:name=".SecondActivity"
android:label="第二个界面">
<intent-filter>
<action android:name="abcd.SecondActivity" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
<activity android:name=".ThirdActivity"
android:label="第三个界面">
<intent-filter>
<action android:name="abcd.SecondActivity" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
<font face = "黑体">运行效果如下所示:
<font face = "黑体">看上面的 gif 动图我们就可以看出来,这种情况下 Android 会让我们选择要运行的 Activity。即当有多个 Action 匹配隐式匹配的条件时,将会弹出选择框供用户选择。
三、Activity 的生命周期
<font face = "黑体">我们就以下面这张 Activity 生命周期图为例子吧:
<img src = "https://img-blog.csdnimg.cn/20200922214426970.jpg?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl8zODQ3ODc4MA==,size_16,color_FFFFFF,t_70#pic_center" width="500" height="420"></img>
<font face = "黑体">一个 Activity 启动的时候会依次调用 onCreate() --> onStart() --> onResume() --> onPause() --> onStop() --> onDestroy()。当执行到 onResume() 的时候这个 Activity 就变成了可操作状态。
3.1、单 Activity 生命周期的调用顺序
- onCreate() 创建 Activity 时调用
- onStart() 当 Activity 界面变为用户可见时调用
- onResume() 当 Activity 界面获取到焦点时调用(<font size = 2>界面按钮可点击,文本框可输入等)
- onPause() 当 Activity 界面失去焦点时调用(<font size = 2>界面按钮不可点击,文本框不可输入等)
- onStop() 当 Activity 界面变为用户不可见时调用
- onDestroy() 当 Activity 被销毁时调用
- onRestart() 当 Activity 再次启动时调用
3.2、多 Activity 生命周期的调用顺序
<font face = "黑体">多Activity的生命周期如下图所示:
<font face = "黑体">上面那张图的操作流程:打开 A activity,点击按钮启动 B activity,在 B activity 中点击返回键。代码运行截图如下:
四、Activity 的启动模式
<font face = "黑体">Activity 的启动模式决定了新生产的 Activity 实例是否重用已存在的 Activity 实例,是否和其他 Activity 实例共用一个 Task。Task 是一个具有栈结构的对象,一个 Task 可以管理多个 Activity,启动一个应用,也就创建一个与之对应的 Task。
4.1、四种启动模式
- standard
<font face = "黑体">默认的启动模式,每次激活 Activity 时(startActivity),都创建 Activity 实例,并放入任务栈; - singleTop
<font face = "黑体">每次激活 Activity 时,判断该 Activity 实例是不是在栈顶,如果是,不需要创建,否则需要创建 Activity 实例; - singleTask
<font face = "黑体">如果要激活的那个 Activity 在任务栈中已经存在了,则不需要创建,只需要把此 Activity 以上的 Activity 实例都出栈,这个时候此 Activity 就到栈顶了,若不存在,就创建 Activity 实例; - singleInstance
<font face = "黑体">只有一个实例,并且这个实例独立运行在一个 Task 中,这个 Task 只有这个实例,不允许有别的 Activity 实例存在。
4.2、四种启动模式代码演示
4.2.1、standard
<font face = "黑体">我们先来看下效果:
可以看到,在 SecondActivity 里面再次启动 SecondActivity,standard 模式下的启动方式会再次创建 SecondActivity 实例。使得任务栈中包含了两个 SecondActivity 实例,所以我们点击返回键只是返回了上一个 SecondActivity,再次按返回键才回到 MainActivity。
<font face = "黑体">主要代码如下所示:
// 启动模式是 standard,不填默认就是 standard
<activity android:name=".SecondActivity"
android:launchMode="standard"/>
// SecondActivity
public class SecondActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_second);
findViewById(R.id.btn_start_self).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
startActivity(new Intent(SecondActivity.this, SecondActivity.class));
}
});
}
}
4.2.2、singleTop
<font face = "黑体">我们还是用上面的例子来演示,只是把 SecondActivity 的启动模式改成 singleTop,我们来看下效果:
可以看到,这个时候在 SecondActivity 里面再次启动自己,是不会创建 SecondActivity 实例的,应该这个时候 SecondActivity已经在栈顶了,而 singleTop 启动模式会判断该 Activity 实例是不是在栈顶,如果是,不需要创建,否则才创建 Activity 实例。
<font face = "黑体">主要代码如下所示:
<activity android:name=".SecondActivity"
android:launchMode="singleTop"/>
<font face = "黑体" color = red>问题1:如果这时候我们再创建一个 ThirdActivity,在 MainActivity 启动 SecondActivity,再在 SecondActivity 里面启动 ThirdActivity,然后在 ThirdActivity 里面启动 SecondActivity,这时候任务栈中 Activity 的实例顺序是怎样的?
<font face = "黑体" color = red>答:任务栈中自底向上的 Activity 实例顺序为 MainActivity-->SecondActivity-->ThirdActivity-->SecondActivity。
4.2.3、singleTask
<font face = "黑体">我们用上面的问题的例子来演示,只是把 SecondActivity 的启动模式改成 singleTask,我们来看下效果:
这个时候任务栈中自底向上的 Activity 实例顺序为 MainActivity–>SecondActivity。因为 SingleTask 启动模式如果栈中存在 Activity 实例会把该 Activity 以上的所有 Activity 实例全部出栈。
<font face = "黑体">主要代码如下所示:
<activity android:name=".SecondActivity"
android:launchMode="singleTask"/>
4.2.4、singleInstance
<font face = "黑体">singleInstance 启动模式和 singleTask 启动模式有点像,都会保证任务栈中只有同一个 Activity 的实例,但是 singleInstance 会创建一个新的 Task。要想演示 singleInstance,我们需要把每个 Activity 所在的栈的 ID 打印出来。例子同上,只是修改启动模式为 singleInstance。
<font face = "黑体">打印日志如下所示:
<font face = "黑体">我们看到 SecondActivity 所在任务栈的 TaskId 是592,而 MainActivity 和 ThirdActivity 所在任务栈的 TaskId 是 591。这就说明 SecondActivity 运行在一个独立的任务栈里面,这个任务栈里面只有 SecondActivity 这一个 Activity 实例。打印 TaskId 的方法如下:
Log.e("activityDemo2TAG", "ThirdActivity所在的task的id为:" + getTaskId());
五、利用 IntentFlag 设置 Activity 的启动方式
<font face = "黑体">讲解这个知识点之前我们先来看一下 Task 和 taskAffinity 这两个概念、
5.1、Task 基本概念
- <font face = "黑体">Task 是一个具有栈结构的容器,可以放置多个 Activity 实例;
- <font face = "黑体">启动一个应用,系统会为之创建一个 Task,来放置根 Activity;
- <font face = "黑体">一个 Activity 启动另一个 Activity 时,默认情况下两个 Activity 是放置在同一个 Task 中的,后者被压入前者所在的 Task 栈,当用户按下返回键,后者从 Task 中被弹出,前者又显示在栈顶。
5.2、taskAffinity 基本概念
- <font face = "黑体">定义了 Activity 实例想要进入的 Task;
- <font face = "黑体">如果一个 Activity 没有显示的指明该 Activity 的 taskAffinity 属性,那么它的这个属性就等于 Application 所指明的 taskAffinity,如果 Application 也没有指明,那么该 taskAffinity 的值就等于包名。
5.3、IntentFlag 的常用值
<font face = "黑体">IntentFlag 的种类很多,我们这里就只挑选几个平时常用的来讲解一下。
5.3.1、FLAG_ACTIVITY_NEW_TASK
<font face = "黑体">系统会寻找或创建一个新的 Task 来放置目标 Activity,寻找时依据目标 Activity 的 taskAffinity 属性进行匹配,如果找到一个 Task 的 taskAffinity 与之相同,就将目标压入此 Task 中,如果查找无果,则创建一个新的 Task,并将该 Task 的 taskAffinity 值设置为目标 Activity 的 taskAffinity,将目标 Activity 放置于此 Task 中 。
5.3.1.1、代码演示
<font face = "黑体">设置 IntentFlag 的方法:
Intent intent = new Intent(MainActivity.this, SecondActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);
<font face = "黑体">$\color{red}{第一种情况}$:以 FLAG_ACTIVITY_NEW_TASK 方式启动 SecondActivity,但是 SecondActivity 不添加 taskAffinity 属性,我们来看下效果:
<font face = "黑体">可以看到,我们虽然以 FLAG_ACTIVITY_NEW_TASK 启动,但是两个 Activity 所在的 Task 还是同一个,这是为什么呢?那是因为如果一个 Activity 没有显示的指明该 Activity 的 taskAffinity 属性,那么它的这个属性就等于 Application 所指明的 taskAffinity,如果 Application 也没有指明,那么该 taskAffinity 的值就等于包名。 也就是说此时 SecondActivity 和 MainActivity 两个 taskAffinity 的值都是包名,所以 SecondActivity 肯定会被放入 MainActivity 所在的栈中了。
<font face = "黑体">$\color{red}{第二种情况}$:以 FLAG_ACTIVITY_NEW_TASK 方式启动 SecondActivity,并且 SecondActivity 设置 taskAffinity 属性:
<activity android:name=".SecondActivity"
android:taskAffinity="flag.newIntent.test"/>
<font face = "黑体">我们来看下效果:
<font face = "黑体">可以看到这时候 SecondActivity 和 MainActivity 已经不在同一个栈里面了。
5.3.2、FLAG_ACTIVITY_SINGLE_TOP
<font face = "黑体">同四种启动模式中的 singleTop,这里就不演示了。
5.3.3、FLAG_ACTIVITY_CLEAR_TOP
<font face = "黑体">同四种启动模式中的 singleTask,这里也不演示。
5.3.4、FLAG_ACTIVITY_REORDER_TO_FRONT
<font face = "黑体">这个启动模式的意思是如果栈中已经存在 Activity 实例,会将它拿到栈顶,不会启动新 Activity,也不会删除它之上的 Activity 实例。
5.3.4.1、代码演示
<font face = "黑体">我们先来看下效果:
<font face = "黑体">我们在 MainActivity 里面启动 SecondActivity,然后在 SecondActivity 里面启动 ThirdActivity,然后再在 ThirdActivity 里面通过 FLAG_ACTIVITY_REORDER_TO_FRONT 的方式启动 SecondActivity,这个时候因为栈中已经有 SecondActivity 实例了,所以会把该实例拿到栈顶,并且不会销毁 SecondActivity 之上的所有实例,所以此时栈自底向上的 Activity 实例顺序是 MainActivity --> ThirdActivity --> SecondActivity。
六、小结
<font face = "黑体">这篇文章主要讲了 Activity 的五种启动方法,包括三种显示启动和两种隐式启动,又讲了单和多 Activity 的生命周期,以及在 AndroidManifest 中通过 lunchMode 设置 Activity 的启动模式和通过Intent.setFlag() 方法设置 Activity 的启动模式。
<font face = "黑体">下一篇文章我们将会讲解在 Activity 中利用 Intent 传参、利用Bundle传递数据、复杂数据的传递以及启动系统 Activity的方法。
Android 四大组件之 Activity 解析(下)
segmentfault 对 mackdown 语法的支持不是很好,有些图片都显示不出来,大家可以去我的掘金查看这篇文章。
一、Activity 回顾
<font face= 黑体>在 完全看懂 Android 四大组件之 Activity(上)中我们已经讲了 Activity 的启动方法、生命周期以及启动模式。这一节我们来讲一下 Activity 之间的传参以及如何启动系统 Activity 这两大知识点。其中 Activity 之间的传参又包括利用 Intent 传参、利用Bundle传参以及复杂数据的传递。
二、Activity 之间的数据传递
2.1、利用 Intent 传递数据
<font face= 黑体>利用 Intent 传递数据主要是调用 Intent.putExtra() 方法,这个方法有两个参数,第一个参数是 name,第二个参数是 value,value 的类型如下所示:
<font face= 黑体>传递数据的具体代码如下所示:
// 1、利用 Intent 传递数据
Intent intent = new Intent(MainActivity.this, SecondActivity.class);
intent.putExtra("str", "Android 开发"); // 传递 String
intent.putExtra("flag", true);
startActivity(intent);
<font face= 黑体>传递的代码已经写完了,那么怎么接收呢?我们可以在 SecondActivity 利用 getIntent() 方法接收数据,具体如下所示:
TextView params = findViewById(R.id.tv_params);
// 接收数据
String str = getIntent().getStringExtra("str");
// 这里的 false 是默认值的意思,如果没有接收到 flag 的值就是 false
boolean flag = getIntent().getBooleanExtra("flag", false);
if (flag) {
params.setText(str);
} else {
params.setText("没有接受到数据");
}
<font face= 黑体>我们来看下效果:
2.2、利用 Bundle 传递数据
<font face= 黑体>利用 Bundle 传递数据主要是是利用 Bundle 先将要传递的数据存储起来,然后再将 Bundle 数据集传递给需要接收的 Activity,我们来看下传递的代码:
// 2、利用 Bundle 传递数据
Intent intent = new Intent(MainActivity.this, SecondActivity.class);
Bundle bundle = new Bundle();
bundle.putString("str", "Android 开发");
bundle.putBoolean("flag", true);
intent.putExtra("myBundle", bundle);
startActivity(intent);
<font face= 黑体>接收 Bundle 也很简单,我们只需要调用 getIntent().getBundleExtra() 方法就可以了,我们来看下代码:
Bundle bundle = getIntent().getBundleExtra("myBundle");
if (bundle != null) {
String str = bundle.getString("str");
boolean flag = bundle.getBoolean("flag");
if (flag) {
params.setText(str);
} else {
params.setText("没有接受到数据");
}
}
<font face= 黑体>Bundle 传递数据跟 Intent 传递数据效果上是完全一样的,只是写法上有点不同而已。
2.3、Activity 间复杂数据的传递
<font face= 黑体>上面这两个方法,可以传递任何基本类型的数据,但是如果想传递一个复杂的数据(比如一个对象),那么要怎么办呢?Android 给我们提供了两种方法来传递复杂类型的数据:
2.3.1、把需要传递的类实现 Serilziable 接口
<font face= 黑体>这里我们创建一个 UserInfo 类来实现 Serilziable 接口,具体代码如下所示:
import java.io.Serializable;
public class UserInfo implements Serializable {
public String username;
public int age;
public int gender;
}
<font face= 黑体>传递的代码如下所示:
// 3、复杂类型的数据传递 实现 Serializable 接口
Intent intent = new Intent(MainActivity.this, SecondActivity.class);
UserInfo userInfo = new UserInfo();
userInfo.username = "Bob";
userInfo.age = 25;
userInfo.gender = 1;
intent.putExtra("userInfo", userInfo);
startActivity(intent);
<font face= 黑体>接收 Serializable 对象,我们需要调用 getIntent().getSerializableExtra() 方法,我们来看下代码:
UserInfo userInfo = (UserInfo) getIntent().getSerializableExtra("userInfo");
if (userInfo != null) {
String str = "名字:" + userInfo.username + " " + "年龄:" + userInfo.age + " " + "性别:" +
(userInfo.gender == 1 ? "男" : "女");
params.setText(str);
}
<font face= 黑体>我们来看下效果:
2.3.2、把需要传递的类实现 Parceable 接口
<font face= 黑体>这里我们创建一个 Order 类来实现 Parceable 接口,我们只需要去重写 describeContents 方法和 writeToParcel 方法就可以了,Creator 是自动生成的,具体代码如下所示:
public class Order implements Parcelable {
public String address;
public boolean isReceived;
public int count;
public Order() {
}
protected Order(Parcel in) {
address = in.readString();
isReceived = in.readByte() != 0;
count = in.readInt();
}
public static final Creator<Order> CREATOR = new Creator<Order>() {
@Override
public Order createFromParcel(Parcel in) {
return new Order(in);
}
@Override
public Order[] newArray(int size) {
return new Order[size];
}
};
@Override
public int describeContents() {
// 只有当对象中存在文件描述符的时候才需要返回 1,通常情况下返回 0 即可
return 0;
}
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeString(address);
dest.writeBoolean(isReceived);
dest.writeInt(count);
}
}
<font face= 黑体>传递的代码如下所示:
// 4、复杂类型的数据传递 实现 Parcelable 接口
Intent intent = new Intent(MainActivity.this, SecondActivity.class);
Order order = new Order();
order.address = "测试地址";
order.isReceived = true;
order.count = 5;
intent.putExtra("order", order);
startActivity(intent);
<font face= 黑体>接收 Parcelable 对象,我们需要调用 getIntent().getParcelableExtra() 方法,我们来看下代码:
Order order = getIntent().getParcelableExtra("order");
if (order != null) {
String str = "地址:" + order.address + " " + "购买数量:" + order.count + " " + "是否已经确认收货:" +
(order.isReceived ? "是" : "否");
params.setText(str);
}
<font face= 黑体>我们来看下效果:
2.4、Activity 数据回传
<font face= 黑体>当第二个 Activity 需要回传数据到第一个 Activity 的时候,我们只需要通过 startActivityForResult() 方法来启动第二个 Activity 即可,当第二个 Activity 关闭的时候,Android 系统会回调第一个 Activity 的 onActivityResult() 方法,在这个方法里面我们可以获取第二个 Activity 回传过来的一些数据。
<font face= 黑体>MainActivity 具体代码如下所示:
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
findViewById(R.id.btn_start).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
// 5、Activity 数据回传
Intent intent = new Intent(MainActivity.this, SecondActivity.class);
startActivityForResult(intent, 1000);
}
});
}
@Override
protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
super.onActivityResult(requestCode, resultCode, data);
String backData = data.getStringExtra("back_data");
Log.e("MainActivityTag", "requestCode:" + requestCode + " " + "resultCode:" + resultCode + " " +
"回传的数据:" + backData);
}
}
<font face= 黑体>SecondActivity 具体代码如下所示:
public class SecondActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_second);
Intent intent = new Intent();
intent.putExtra("back_data", "回传数据是。。。。。。。。");
setResult(RESULT_OK, intent);
}
}
<font face= 黑体>结果如下所示:
三、启动系统的 Activity
<font face= 黑体>Android 系统常用的 Activity 组件包括拨打电话、发送短信以及打开相机,启动方法分别是:
- <font face= 黑体>intent.setAction(Intent.ACTION_DIAL);
- <font face= 黑体>intent.setAction(Intent.ACTION_SENDTO)
- <font face= 黑体>intent.setAction(MediaStore.ACTION_IMAGE_CAPTURE)
<font face= 黑体>具体代码如下所示:
拨打电话
Intent intent = new Intent(); intent.setAction(Intent.ACTION_DIAL); startActivity(intent);
发送短信
Intent intent = new Intent(); intent.setAction(Intent.ACTION_SENDTO); Uri smsToUri = Uri.parse("smsto:" + 10086); intent.setData(smsToUri); intent.putExtra("sms_body", "短信内容"); startActivity(intent);
打开相机
Intent intent = new Intent(); intent.setAction(MediaStore.ACTION_IMAGE_CAPTURE); startActivity(intent);
<font face= 黑体>具体效果如下所示:
四、小结
<font face= 黑体>到这里为止,我们已经讲了 Activity 的五种启动方法、生命周期、四种启动模式、Activity 之间数据的传递和如何启动系统 Activity 组件。
今天关于【Android】Android四大组件之Activity和android的4大组件的讲解已经结束,谢谢您的阅读,如果想了解更多关于Android 四大组件 (一) Activity 生命周期、Android 四大组件之 Activity、Android 四大组件之 Activity 解析(上)、Android 四大组件之 Activity 解析(下)的相关知识,请在本站搜索。
本文标签: