前言
Activity
,是 Android 的四大组件之一。在 Android 开发当中,是最常用的一种组件,那么 Activity 的生命周期是怎么样的呢?
Activity 生命周期
Activity 的生命周期可以分为两个部分内容,一部分是典型情况下的生命周期,另一部分是异常情况下的生命周期。
典型情况下的生命周期
所谓典型情况下的生命周期,是指在有用户参与的情况下,Activity 所经过的生命周期的变化。在正常的情况下,Activity 会经历如下的生命周期。
onCreate
:表示 Activity 正在被创建,这是生命周期的第一个方法。在这个方法中,我们可以做一些初始化工作,比如调用 setContentView 去加载界面布局资源、初始化 Activity 所需数据等。Activity 必须有 onCreate 方法才会开启生命周期。onRestart
:表示 Activity 正在重新启动。一般情况下,当当前 Activity 从不可见重新变为可见状态时,onRestart 就会被调用。这种情形一般是用户行为所导致的,比如用户按 Home 键切换到桌面或者用户打开了一个新的 Activity,这时当前的 Activity 就会暂停,也就是 onPause 和 onStop 被执行了,接着用户又回到这个 Activity,就会出现这种情况。onStart
:表示 Activity 正在被启动,即将开始,这时 Activity 已经可见了,但是还没有出现在前台,还无法和用户交互。这个时候其实可以理解为 Activity 已经显示出来了,但是我们还是看不到的。onResume
:表示 Activity 已经可见了,并且出现在前台并开始活动。要注意这个和 onStart 的对比,onStart 和 onResume 都表示 Activity 已经可见,但是 onStart 的时候 Activity 还在后台,onResume 的时候 Activity 才显示到前台。onPause
:表示 Activity 正在停止,正常情况下,onStop 就是被调用。在特殊情况下,如果这个时候快速地回到当前 Activity,那么 onResume 会被调用。这个时候我们可以做一些存储数据、停止动画等工作,但是不能做耗时操作。因为这样会影响到新 Activity 的显示,onPause 必须先执行完,新 Activity 的 onResume 才会执行。onStop
:表示 Activity 即将停止,可以做一些稍微重量级的回收工作,同样不能太耗时。onDestroy
:表示 Activity 即将被销毁,这是 Activity 生命周期中的最后一个回调。在这里,我们可以做一些回收工作和最终的资源释放。
正常情况下,Activity 的常用生命周期只有上面的 7 个,我们可以了解一下 Activity 各种生命周期的切换过程。
Activity 生命周期的切换过程
Activity 各种生命周期的切换过程就如上图中表示的一样,主要分为以下几种情况:
-
在一个特定的 Activity 中,第一次启动,回调如下:
onCreate->onStart->onResume
; -
当用户打开新的 Activity 或者切换到桌面的时候,回调如下:
onPause->onStop
; -
当用户再次回到(返回)原 Activity 时,回调如下:
onRestart->onStart->onResume
; -
当用户按 back(返回)键回退时,回调如下:
onPause->onStop->onDestroy
; -
当 Activity 被系统回收后再次打开,生命周期方法回调过程是
onCreate->onStart->onResume
; 注意:只是生命周期方法一样,不代表所有的过程都一样。 -
从整个生命周期来说,onCreate 和 onDestroy 是配对的,分别标识这 Activity 的创建和销毁,并且只有可能有一次调用。从 Activity 是否可见来说,onStart 和 onStop 是配对的,随着用户的操作或者设备屏幕的点亮和熄灭,这两个方法被调用多次;从 Activity 是否在前台来说,onResume 和 onPause 是配对的,随着用户操作或者设备屏幕的点亮和熄灭,这两个方法也有可能被调用多次。
异常情况下的 Activity 生命周期
异常情况下的生命周期是指 Activity 被系统回收或者由于当前设备的 Configuration
(配置)发生变化从而导致 Activity 被销毁重建。异常情况的产生可能是当资源相关的系统配置发生改变以及系统内存不足时,Activity 就有可能被杀死。
情况 1
资源相关的系统配置发生改变导致 Activity 被杀死并重新创建
用最简单的图片来说,当我们把一张图片放 drawable 目录下,就可以通过 Resources 来获取这张图片。
同时为了兼容不同的设备,我们可能还需要在其他一些目录放置不同的图片,比如 drawable-mhdpi、drawable-xhdpi、drawable-xxhdpi 等。
这样当应用程序启动时,系统就会根据当前设备的情况去加载合适的 Resources 资源,比如说横屏手机和竖屏手机会拿到两张不同的图片(设置 landscape 或者 portrait 状态下的图片)。
比如说当前 Activity 处于竖屏状态,如果突然旋转屏幕,由于系统配置发生了改变,在默认情况下,Activity 就会被销毁并且重新创建,当然我们也可以阻止系统重新创建我们的 Activity。
防止应用在手机运行横竖屏自动切换,我们可以在 AndroidManifest 中设置 landscape 或者 portrait。
异常情况下 Activity 重建过程
如上图所示,当系统配置发生改变后,Activity 会被销毁,其 onPause、onStop、onDestroy 都会被调用,同时由于 Activity 是在异常情况下终止的,系统会调用 onSavaInstanceState 来保存当前 Activity 的状态。
这个方法的调用时机是在 onStop 之前,它和 onPause 没有既定的时序关系,它既可能在 onPause 之前调用,也可能在 onPause 之后调用。但是我们需要注意的是:
onSavaInstanceState 方法只会出现在 Activity 被异常终止的情况下,正常情况下系统不会回调这个方法。
当 Activity 被重新创建后,系统会调用 onSavaInstanceState,并把 Activity 销毁时 onSavaInstanceState 方法保存的 Bundle 对象作为参数同时传递给 onRestoreInstanceState 和 onCreate 方法。
所以我们可以通过 onRestoreInstanceState 和 onCreate 方法来判断 Activity 是否被重建。如果 Activity 被重建了,那么我们就可以取出之前保存额数据并恢复,从时序层面来说,onRestoreInstanceState 的调用时机在 onStart 之后。
注意:
- 在调用 onSavaInstanceState 和 onRestoreInstanceState 方法时,系统会自动为我们做一定的恢复工作。
- 每个 View 都有 onSaveInstanceState 和 onRestoreInstanceState 这两个方法。
- 接收位置可以是 onRestoreInstanceState 和 onCreate 方法,区别是:onRestoreInstanceState 如果被调用,参数 Bundle 一定是有值的,在 onCreate 中需要判断参数是否为 null。
- onSavaInstanceState 和 onRestoreInstanceState 只有在 Activity 异常终止时才会调用来储存和恢复数据,正常销毁的 Activity 生命周期中不会调用,比如:旋转屏幕,按 Home 键,启动新 Activity 等。
情况 2
资源内存不足导致低优先级的 Activity 被杀死
Activity 优先级情况:
- 前台 Activity——正在和用户交互的 Activity,优先级最高;
- 可见但非前台 Activity——Activity 中弹出的对话框,导致 Activity 可见但无法与用户直接产生交互;
- 后台 Activity——已经被暂停的 Activity,比如执行了 onStop,优先级最低。
上面是 Activity 的优先级情况,当系统内存不足时会根据上述的优先级去杀死目标 Activity 所在的进程,并在后续通过 onSavaInstanceState 和 onRestoreInstanceState 方法来存储和恢复数据。
注意:
如果一个进程中没有 Android 四大组件在执行,那么这个进程将很快被系统杀死。所有一写后台工作不适合在脱离 Android 四大组件而独自运行在后台中,这样进程很容易被杀死。比较好的方式是将后台工作放入 Service 中保证进程有一定的优先级,这样就不会轻易被系统杀死。
看到这里,可能大家都和我一样有一个疑问:既然 Activity 是在被销毁时才会异常的生命周期,那么有没有办法让 Activity 不重新创建呢?答案是:有的,那么下面来看一下什么办法。
不让 Activity 重新创建
不想让 Activity 在屏幕旋转的时候重新创建时,我们就可以给 configChanges
属性添加 orientation
这个值,如下所示:
android:configChanges="orientation"
如果我们想指定多个值,可以用“|”连接起来,比如 android:configChanges=”orientation|keyboardHidden”
。系统配置中所含地项目是非常多的, 但是我们常用的只有 locale、orientation 和 keyboardHidden 这三个选项。下面介绍一下这三个属性:
- local:设备的本地位置发生了变化,一般指切换了系统语言;
- keyboardHidden:键盘的可访问性发生了变化,比如用户调出了键盘;
- orientation:屏幕方向发生了变化,比如旋转了手机屏幕。
评论区