activity生命周期的详解
aicitvity翻译成中文意思是活动,主要用于和用户交互,提供了一个窗口用于存放ui布局和控件,主要表现形式是以一个全屏的窗口,或者悬浮窗以及嵌套在其它activity里面。控制activity的布局使用setContentView方法,这个方法有很多重载,使用最多的是传递布局资源,window会将该布局填充到最高层。acitivity最重要的是理解它的回调和生命周期,以便在开发过程中更好的控制数据的初始化和持久化。
作为activity的子类,最重要的两个方法是onCreate和onPause,onCreate主要用于初始化与用户交互的控件和布局以及一些数据的读取,onPause主要用于将一些用户操作的数据进行持久化。这两个方法一般都会重写,主要不要在此做耗时操作,比如读取网络数据(android4.0之后已经不允许在主线程进行网络操作了),否则可能会造成crash。
activity主要有四种状态:
(1)activity处于活动栈的栈顶即在window的最上层,此时称为这个aciticity是活动状态的(active或者running),用户可以与应用进行交互。
(2)activity处于可见状态但失去了焦点,主要表现是不能接收用户的交互。通常是因为有一些透明主题的activity或者类似AlertDialog之类非全屏的view覆盖在上面。此时activity仍然保持着保持着所有的数据和状态并且依附在window管理器,当可用内存很低时,可能会被系统杀死。称为paused状态。
(3)activity完全被覆盖时,仍然拥有所有的成员状态和资料,但是window却已经被隐藏再也不会重新呈现,只要内存需要随时都会被系统给杀死,称为stopped状态。
(4)activity处于paused和stopped状态时,会被系统要求结束或者简单粗暴的结束它的进程。当再次呈现时必须重新开始和恢复之前的状态和数据,称为destoryed状态。
根据上述的activity状态。可将activity的生命周期细分为一下3类:
activity的生命周期可分为以下3种:
(1)完整生命周期,始于onCreate终于onDestroy,所有的全局变量和控件初始化都应该在onCreate完成,在onDestroy应该释放所有的资源。
(2)可见生命周期,始于onStart终于onStop,在这个生命周期里,activity可能不能和用户进行交互,但却是可见的,这两个方法会被调用多次。
(3)前台生命周期,始于onResume终于onPause,此时activity位于屏幕的最上层并且可以和用户进行交互,这两个方法也会被频繁的调用。
了解了上述所说的activity状态和生命周期,现在看一下activity所有的生命周期的回调方法,先对activity完整生命周期有个大概了解。
public class Activity extends ApplicationContext {
* protected void onCreate(Bundle savedInstanceState);
*
* protected void onStart();
*
* protected void onRestart();
*
* protected void onResume();
*
* protected void onPause();
*
* protected void onStop();
*
* protected void onDestroy();
* }
接下来通过一个例子来详细了解生命周期的过程,编写一个activity的子类,并通过Log来了解生命周期的回调过程,代码如下:
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Log.i("test", "onCreate");
}
@Override
protected void onStart() {
super.onStart();
Log.i("test", "onStart");
}
@Override
protected void onResume() {
super.onResume();
Log.i("test", "onResume");
}
@Override
protected void onPause() {
super.onPause();
Log.i("test", "onPause");
}
@Override
protected void onStop() {
super.onStop();
Log.i("test", "onStop");
}
@Override
protected void onDestroy() {
super.onDestroy();
Log.i("test", "onDestroy");
}
@Override
protected void onRestart() {
super.onRestart();
Log.i("test", "onRestart");
}
}
接着我们按返回键,销毁activity。
我们可以看到回调的顺序是onCreate->onStart->onResume->onPause->onStop->onDestory。
现在我们重新开启应用,然后按home键,再打开应用,最后按返回键销毁activity的log日志。
启动应用:
按下home键:
重新打开应用:
销毁activity:
调用顺序是onCreate->onstart->onResume->onPause->onStop->onRestart->onStart->onResume->onPause->onStop->onDestory。
下面解释一下各个回调发生情况:
(1)onCreate:activity整个生命周期仅回调一次,用于创建activity。
(2)onStart:activity处于可见但是没有获取到焦点的情况,当activity从后台(不可见)重新变成前台(可见),会被调用。
(3)onResume:activity位于window的最顶层,可以接受用户的交互时回调。
(4)onRestart:activity从stopped状态迅变成active状态时回调。
(5)onPause:activity开始失去焦点,开始向后台过渡时回调。
(6)onStop:activity失去焦点,开始向不可见状态过渡时回调。
(7)onDestroy:activity处于销毁状态是回调,生命周期仅回调一次。
刚才讲述了两种情况下生命周期的回调变化,现在主要解释第二种,通过对第二种情况的了解,就能够 理解第一种了。当我们打开应用,acitivity会被调用,会将自身依附在window进行视图渲染,此时onCreate被调用。然后会进行呈现,再然后获取焦点,所以onStart,onResume被调用。当我们按下home键,activity开始失去焦点并向后台转变,此时onPause,onStop会被调用。当我们再次打开应用时,由于当前activity还是位于栈顶,所以会被唤醒,重新呈现和获取焦点,从stopped状态转为active状态,所以onRestart,onStart,onResume会被调用。最后我们销毁activity,activity会因为失去焦点然后变成不可见状态最后被回收,便会调用onPasue,onStop,onDestory。我们要注意的是切记不要在onpause方法使用耗时的操作,因为只有旧的activity的onPause回调完成,新的activity的才会启动,如果进行了耗时操作,可能会导致页面跳转卡顿严重的灰奔溃掉。
下面分析一下异常情况下activity生命周期的回调。
在异常情况下,activity除了有上述的回调方法,还会有两个新的回调方法,分别是onSaveInstanceState和onRestoreInstanceState两个回调方法。其中onSaveInstanceState是用于保存activity的状态数据,onRestoreInstanceState用于恢复activity状态数据。什么情况下会出现异常呢,最典型的是屏幕倒置,突然由竖屏状态变成横屏状态,从而使配置发生改变,因为android有资源加载机制,当配置发生改变时,会重新加载合适的配置文件,所以activity的会快速的经历一个由销毁到重新启动的过程。
为了方便理解,我们来看一下例子,我们在刚刚的那个例子中添加如下代码。
@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
Log.i("test", "onSaveInstanceState");
}
@Override
protected void onRestoreInstanceState(Bundle savedInstanceState) {
super.onRestoreInstanceState(savedInstanceState);
Log.i("test", "onRestoreInstanceState");
}
接下来我们启动应用并倒置屏幕,看看打印的log:
启动时:
07-08 08:02:53.520 12553-12553/com.example.hy.androidart I/test: onCreate
07-08 08:02:53.533 12553-12553/com.example.hy.androidart I/test: onStart
07-08 08:02:53.534 12553-12553/com.example.hy.androidart I/test: onResume
倒置屏幕:
07-08 08:03:19.504 12553-12553/com.example.hy.androidart I/test: onPause
07-08 08:03:19.504 12553-12553/com.example.hy.androidart I/test: onSaveInstanceState
07-08 08:03:19.504 12553-12553/com.example.hy.androidart I/test: onStop
07-08 08:03:19.504 12553-12553/com.example.hy.androidart I/test: onDestroy
07-08 08:03:19.546 12553-12553/com.example.hy.androidart I/test: onCreate
07-08 08:03:19.550 12553-12553/com.example.hy.androidart I/test: onStart
07-08 08:03:19.551 12553-12553/com.example.hy.androidart I/test: onRestoreInstanceState
07-08 08:03:19.551 12553-12553/com.example.hy.androidart I/test: onResume
我们发现activity会快速的从一个active状态到destroy状态过渡并重新启动一个activity,在onpause执行后会执行onSaveInstance进行数据和状态保存,这两个方法并没有先后顺序,但是一定在onStop执行前执行。在新的activity启动时会调用onRestoreInstanceState方法进行数据恢复。如何来判断一个activity是否重新启动呢,有两种方法。一种是通过判断onCreate(Bundle savedInstanceState) 的savedInstanceState参数是否为Null,空的话表示不是重新启动,不为空说明是重新启动的。还有一种是看是否回调了onRestoreInstanceState方法,如果调用了必然是重新启动了。如果想在配置改变时不重新加载activity,可以在AndroidManifest.xml配置相应的activity的android:configChanges属性的值。
还有一种异常情况时,内存不够用时,进程会按照优先级来回收activity。其中可见状态且持有焦点的activity优先级最高其次是可见但未持有焦点的activity最后是后台activity。当内存紧张时,优先级越低的activity被回收的概率越大。所以如果我们想要执行耗时的操作,建议用service这样会使进程的优先级高,从而不至于被系统杀死进程,一个空的进程是很容易被回收杀死的。