一、活动生命周期的意义
Activity(活动)是一种可以包含用户界面的组件,主要用于与用户进行交互。也就是说,在用户与界面进行交互之前,必须要进行特定的初始化操作。再者,Android 操作系统是一个多任务(Multi-Task) 的操作系统,用户在听歌的同时也可以打开其他 app。但是每一个程序的开启都会耗费一定的系统资源,当运行的程序过多,系统资源又没有及时的回收,容易导致系统运行变慢甚至不稳定。
为了解决这些问题,Android 引入一个新的机制—生命周期 (Life Cycle) 。Android 应用程序的生命周期是由 Android 框架进行管理的,并不是由应用程序直接控制。每一个应用程序都会产生一个进程,当系统内存不足的时候,会依照优先级进行进程的回收。但是,无论是使用者还是开发者,都没有办法确定哪一个进程会被回收。为了防止数据丢失和其他问题,需要了解生命周期。
二、简介生命周期的七个阶段
Activity 类中定义了七个回调方法,覆盖了活动生命周期的每一个环节。
1. onCreate() (不可见)每个活动都会重写这个方法,他会在活动第一次被创建的时候调用。在这个方法中完成活动的初始化操作,比如加载布局,绑定事件等。
2. onStart() (可见)这个方法在活动由不可见变为可见的时候调用,只是活动还没有在前台显示。。
3. onResume() (可见)这个方法在活动准备好和用户进行交互的时候调用,并且,当且活动处于返回栈的栈顶(稍后解释何为返回栈的栈顶),并处于运行状态。
4. onPause() (可见)这个方法在系统准备去启动或恢复另一个活动的时候调用(当前活动还在栈顶)。我们通常在这个方法中释放一些CPU资源并保存一些关键数据,但是,这个方法的执行一定要快,不然会影响到新的栈顶活动的使用。
5. onStop() (不可见)这个方法活动完全不可见的时候调用,活动仅在后台工作。他和 onPause() 的区别在于,如果新的活动是对话框式的(即没有完全覆盖这个界面),那么只有 onPause() 被调用, onStop() 方法则不会被调用。
6. onDestory() (不可见)这个方法在活动被销毁之前调用,在这之后活动将处于销毁状态,是生命周期最后执行的方法。
7. onRestart() (可见)这个方法在活动由停止(Stop)状态变为运行(Start)状态之前调用,将活动由不可见变为可见,也就是活动被重新启动了。
为了加强理解,我们来做一个类比(建议自己思考)。活动的生命周期可以类比为一个人的生命周期。
onCreate 相当于一个人还在娘胎的阶段,完成必要的初始化工作,此时人还不可见。
onStart 于人出生了,此时他已经可见,但是还没有和这个社会产生互动。
onResume 人开始去工作,和社会产生了关系。
onPause 人由了自己的小孩(新的Activity),此时孩子在他的前面,他的行为孩子的抑制。
onStop 人到了一定岁数之后退休,和社会基本没有联系。
onRestart 人在退休之后,重新上班,回到 Start 状态,即准备和社会产生联系。
onDestory 很容易理解,就是去世。
三、返回(任务)栈。
前面我们讲到调用 onResume 方法的活动处于返回栈的栈顶,什么是返回栈呢?
我们知道,Android 中的活动是可以叠加的,当我们启动一个新的活动时,会将原先的活动覆盖。当我们按 back 键返回或者调用 finish() 方法时,会销毁最上面的活动,然后下面的活动就会显示出来。
其实,Android 是用一个任务(Task)来管理活动的,一个任务就是一组在栈中的任务的集合。这个栈就是返回栈,栈是一种后进先出的数据结构,并且,MainActivity 处于栈的最底端。在默认情况下,启动一个新的活动,他会在返回栈中入栈,并处于栈的栈顶。按 back 键或调用 finish() 方法后,这个活动就会出栈,系统总是会显示处于栈顶的活动。
四、具体讲讲几个方法
1. onCreate() 完成活动的初始化操作(用户打开界面首先看见的UI效果一般都会在 onCreate 方法中就被加载),例如,加载布局、绑定事件,调用 setContentView() 方法等。
但是不可以将所有的初始化操作都放在 onCreate 中实现。
一个原因是,活动调用 onCreate() 方法时,是不可见的。假设活动需要加载一个动画,我们知道,动画会占据较多的内存资源,在 onCreate() 加载不仅不会增加用户体验,还会消耗资源。
另一个原因是,在整个活动的生命周期中,onCreate() 方法只会调用一次,如果有一些数据需要在特定情况下再次初始化,那么在onCreate() 方法中将其初始化就无法满足需求。
2. onStart() 这个方法中进行的初始化一般配合 onStop() 方法使用,当界面由不可见变为可见时,需要进行的初始化工作可以选择在 onStart() 中实现。
同样,也不可以将所有的初始化操作都放在 onStart() 方法中实现。虽然,在 onStart() 方法中调用 setContentView() 和 findViewById() 方法也没有问题,但是,在 onCreate() 方法的注释中明确建议,这两个方法在 onCreate() 中调用。
3. onResume() 这个方法并不是 Activity 对用户是可见的最好的指示器。但是,在这个方法的介绍中说明,这是开始画动画的好地方,同时,如果你需要向用户申请独占设备时,也可以在这个方法中实现。同样的,这个方法配合 onPause() 方法进行使用。
4. onPause() 回调这个方法后,可能会回调 onStop() 方法,但是也有可能会回到 onResume() 方法。我们可以在 onPause() 方法中进行数据存储、动画停止、资源回收等操作。
另外,只有当上一个活动回调完 onPause() 方法后,下一个活动才可以回调 onResume() 方法。所以 onPause() 方法不能太耗时,不然会影响到新 Activity 的显示。下面是 MainActivity 的创建一直到跳转显示 NormalActivity 的生命周期方法回调。
//MainActivity 创建
MainActivity: onCreate
MainActivity: onStart
MainActivity: onResume
//跳转到 NormalActivity
MainActivity: onPause
NormalActivity: onCreate
NormalActivity: onStart
NormalActivity: onResume
MainActivity: onStop
//可以看见,先回调 MainActivity 中的 onPause() 方法,再回调 NormalActivity 中的三个方法,最后才是MainActivity 中的 onStop() 方法
5. onStop() 在这个方法中进行资源的回收。但是,我们不能将全部的资源都放在这个方法中才回收。
一是独占设备的问题。假设我们在 ActivityA 中打开了相机,在 ActivityB 中同样需要用到相机,像在 onPause() 方法中我们说明的一样,在ActivityB 回调完三个方法后,ActivityA 的 onStop() 方法才会回调,那么在 ActivityB 中打开相机时就会遇到阻塞导致无法正确打开。
二是,当内存不足导致系统自动回收进程的情况下,onStop() 方法并不会被回调。