Activity的生命周期

Activity作为Android的四大组件之首,生命周期当然是重中之重了。
虽然都是老生常谈的面试题了。。。但是被面试官问到了,还是不会的话,
尴尬不是一点点啊。(⊙﹏⊙)b
Activity—其实我更愿意喊它一声“界面”呗。我们在手机上看到的一个窗口,就是它啊。
它的生命周期也分为两种情况:
第一:正常情况下的生命周期
第二:非正常情况下的生命周期:比如屏幕翻转或者内存不足,被kill掉了。

一、 Activity有哪些生命周期方法

先来过滤一下,一共有哪些生命周期的方法吧!

  • onCreate:表示窗口正在被创建,比如加载layout布局文件啊(setContentView)。 所以我们可以在这个方法中,做一些初始化的操作。

  • onStart:表示Activity正在被启动,即将开始,此时的窗口已经可见了,但是还没有出现在前台,所以无法和用户进行交互。也就是说此时的窗口正处在 不可见—>可见 的过程中。

  • onRestart:表示窗口正在重新启动。在什么场景下会调用这个呢?比如:从A页面进入B页面,然后点击BACK键(或者自己的返回上一页的按钮)回到A页面,那么就会调用A页面的onRestart方法了。。(当前也牵扯到A和B页面的其他生命周期方法的调用,这个我们后面再详细说明)
    再比如:点击HOME键回到桌面,然后通过点击任务栏或者点击应用图标再次进入A页面,都可以触发调用这个方法

  • onResume:表示此时的窗口已经可见了,显示在前台并且进行活动了,我们也可以与窗口进行交互了。

  • onPause:表示窗口正在停止,这是我们可以做一些存储数据、或者停止动画等一些不太耗时的操作,因为会影响到下一个Activity的显示。onPause执行完成之后,新的Activity的onResume才会执行。

  • onStop:表示窗口即将停止,此时,可以做一些稍微重量级的回收工作,但是也不能太耗时哈。

  • onDestroy:表示窗口即将被销毁。这是Activity生命周期中的最后一步了。这里,我们可以做一些回收工作和最终的资源释放工作。

下面,我们暴露一张图,来详细的描述一下窗口的生命周期的切换过程:
(此图是任玉刚的《Android开发艺术探索》里面的,懒,不想自己画了。)
Activity的生命周期_第1张图片

二、正常情况下,Activity的生命周期调用过程

然后我们来梳理一下几种情况下,生命周期的方法调用顺序是怎么样的。

  1. 启动一个特定的Activity时,第一次启动,生命周期回调如下:
    onCreate –> onStart –> onResume

  2. 当用户打开新的Activity或者切换到桌面的时候,回调如下:
    onPause –> onStop
    但是有一种特殊的情况,如果新的Activity采用了透明的主题,那么当前Activity不会回调onStop

  3. 当用户再次回到原Activity时,回调如下:
    onRestart –> onStart –> onResume

  4. 当用户点击Back键回退时,回调:
    onPause –> onStop –> onDestory

  5. 当Activity被系统回收后再次打开时,回调onCreate –> onStart –> onResume(和过程1一样,但是只是生命周期的回调过程一样,这里还是有一些其他过程的区别的,比如回收时onSaveInstanceState的方法的调用,以及打开时onRestoreInstanceState的调用)
  6. 在生命周期中,onCreate和onDestroy是对应的,创建和销毁,并且在生命周期过程中,只被调用一次。从Activity是否可见来说,onStart和onStop是配对的,这两个方法有可能会被多次调用。从Activity是否在前台来说,onResume和onPause是配对的,也有可能会被多次调用。

其中有两个问题:
第一:onStart和onResume,onPause和onStop差不对,但是又有什么本质的不同呢?
第二:当从A 窗口打开B窗口时,B窗口的onResume和A的onPause方法哪个先执行呢?

首先第一个问题:
从上面的描述中就知道了,虽然差不多,但是角度还是不通的。onStart和onStop从Activity是否可见来说的,onResume和onPause从Activity是否在前台来说的。其他的就没有什么区别了。

第二问题:
自己实践一下就知道了,先是A的onPause方法调用结束之后,才会执行B窗口的onResume方法。当然还是从源码了解的更彻底。。。请参考任玉刚的《Android开发艺术探索》或者自己去 AndroidXRef 看吧。

三、非正常情况下,Activity的生命周期调用过程

非正常情况下,比如屏幕的旋转,或者内存不够用的情况下,由系统的回收操作造成的非前台的Activity被意外杀死的情况。
盗一图,来源:任玉刚的《Android开发艺术探索》
Activity的生命周期_第2张图片

屏幕旋转下的生命周期

我们用实例来说明
在LunchAActivity中,我们在Logcat中打印所有的生命周期方法

import android.content.Intent;
import android.os.Bundle;
import android.os.PersistableBundle;
import android.support.v7.app.AppCompatActivity;
import android.widget.Button;
import android.widget.TextView;

import butterknife.BindView;
import butterknife.ButterKnife;
import butterknife.OnClick;
import demo.learn.com.learndemo.R;
import demo.learn.com.learndemo.utls.LogUtils;

public class LunchAActivity extends AppCompatActivity {
    @BindView(R.id.btn_jump)
    Button btnJump;
    @BindView(R.id.tv_save)
    TextView tvSave;
    private String saveValues = "";

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_lunch_a);
        ButterKnife.bind(this);
        LogUtils.logE("LunchAActivity", "onCreate");
    }

    @Override
    protected void onSaveInstanceState(Bundle outState) {
        super.onSaveInstanceState(outState);
        outState.putString("savevalue", "意外保存的结果");
        LogUtils.logE("LunchAActivity", "onSaveInstanceState");
    }

    @Override
    public void onSaveInstanceState(Bundle outState, PersistableBundle outPersistentState) {
        super.onSaveInstanceState(outState, outPersistentState);
    }

    @Override
    protected void onRestoreInstanceState(Bundle savedInstanceState) {
        super.onRestoreInstanceState(savedInstanceState);
        saveValues = savedInstanceState.getString("savevalue");
        LogUtils.logE("LunchAActivity", "onRestoreInstanceState");
    }

    @Override
    public void onRestoreInstanceState(Bundle savedInstanceState, PersistableBundle persistentState) {
        super.onRestoreInstanceState(savedInstanceState, persistentState);
    }

    @Override
    protected void onRestart() {
        super.onRestart();
        LogUtils.logE("LunchAActivity", "onRestart");
    }

    @Override
    protected void onStart() {
        super.onStart();
        LogUtils.logE("LunchAActivity", "onStart");
    }

    @Override
    protected void onResume() {
        super.onResume();
        LogUtils.logE("LunchAActivity", "onResume");
        tvSave.setText(saveValues);
    }

    @Override
    protected void onPause() {
        super.onPause();
        LogUtils.logE("LunchAActivity", "onPause");
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        LogUtils.logE("LunchAActivity", "onDestroy");
    }

    @OnClick(R.id.btn_jump)
    public void onViewClicked() {
        Intent intent = new Intent(this, LunchBActivity.class);
        startActivity(intent);
    }
}

正常打开页面的生命周期回调如下:
Activity的生命周期_第3张图片

然后,旋转屏幕之后,打印出来的生命周期如下:
Activity的生命周期_第4张图片
即在onDestory之前先调用onSaveInstanceState保存一些恢复页面时需要的数据,然后重新走onCreate–>onStart方法,在onResume之前调用onRestoreInstanceState获取存储的数据,然后可以在onResume方法中,将获取的数据赋值给控件等等操作。
注意这里不走onRestart方法,这里是销毁窗口之后并重建,慢慢领会一下,实在不行,自己动手操作实践一遍就哦了。

资源内存不足导致低优先级的Activity被杀死的情况下

这种情况不好模拟,但是保存数据的过程和恢复数据的过程是一模一样的。
而且回收过程中,牵扯到Activity的优先级,所以我们来讨论一下Activity的优先级:

  • 前台Activity
    正在和用户进行交互的窗口,优先级最高

  • 可见但是非前台的Activity
    比如Activity中弹出一个对话框,导致Activity可见但是不可交互

  • 后台Activity
    已经被暂停的Activity,比如执行了onStop方法的窗口,优先级最低

    当系统内存不足时,就会按照优先级去kill掉目标Activity所在的进程,并执行onSaveInstanceState和onRestoreInstanceState来保存和恢复数据。
    而且一个进程中如果没有四大组件在运行,那么这个进程很容易被杀死。
    所以一些后台进程不适合脱离四大组件独立运行。最好将一些重要的后台操作放在Service中,这样保证一定的优先级,就不会轻易被系统杀死。

如果我们想让屏幕在旋转时不销毁并重建页面,可以在AndroidManifest.xml中给Activity配置一下configChanges,如下图
Activity的生命周期_第5张图片
两个参数缺一不可
并且在Activity中重新onConfigurationChanged方法
Activity的生命周期_第6张图片
这样在旋转屏幕时,就不会销毁并重建Activity了。只会调用这个onConfigurationChanged回调方法。
当然我们也可以禁止屏幕旋转,通过 android:screenOrientation=”portrait”只让屏幕保持竖屏。

待定……
下一章节,复习一下Activity的四中启动模式。。。
Activity的生命周期_第7张图片

你可能感兴趣的:(Android)