前言
很高兴遇见你~ 欢迎阅读我的文章。
关于Activity生命周期的文章,网络上真的很多,有很多的博客也都讲得相当不错,可见Activity的重要性是非常高的。事实上,我猜测每个android开发者接触的第一个android组件都是Activity。我们从新建第一个Activity开始,运行了代码,看到模拟机上显示了一个MainActivity标题和一行HolleWorld,从此打开Android世界的大门。
本篇文章讲解的重点是Activity的生命周期,在文章的最后也会涉及Activity的设计。不同于其他的博客设计,文章采用系统化的讲解,关于Activity生命周期的相关知识基本都会涉及到。
文章第一部分讲解关于Activity状态的认知;
第二部分全面讲解activity生命周期回调方法;
第三部分是分析不同情景下的生命周期回调顺序:
第四部分是原码分析;
最后一部分是从更高的角度来思考activity以及生命周期。
文章全面的同时,免不了篇幅过长,造成阅读障碍。读者可先观看目录,查找最感兴趣的章节阅读,如若有时间,仍建议阅读全文。
这是笔者Android全面解析系列的新一篇文章。前几篇文章在公众号发布时,虽然受到了一些好评,但也被诟病文章实在是太长了。笔者也思考了是否删减章节、切割部分等等。后来思考了一下,我写这一系列文章的初衷就是为了能够系统地讲解每个知识点,而不是零散地介绍某个孤立的点。笔者更喜欢看书的原因,是书本会更加系统全面地讲每个知识点,让我对整个知识有系统的认知,而不像网络博客,把每个知识点都孤立起来了,很难做到有系统的感知。
本文长达一万多字,生命周期相关的知识点都有讲到。限于笔者的认知,有一些地方讲解错误或者没有涉及到,欢迎评论区留言一起探讨,共同打造一篇可以帮助到更多读者的文章。
那么,我们开始吧。
生命状态概述
Activity是一个很重要、很复杂的组件,他的启动不像我们平时直接new一个对象就完事了,他需要经历一系列的初始化。例如"刚创建状态",“后台状态”,“可见状态”等等。当我们在界面之间进行切换的时候,activity也会在多种状态之间进行切换,例如可见或者不可见状态、前台或者后台状态。当Activity在不同的状态之间切换时,会回调不同的生命周期方法。我们可以重写这一些方法,当进入不同的状态的时候,执行对应的逻辑。
在ActivityLifecycleItem`抽象类中定义了9种状态。这个抽象类有很多的子类,是AMS管理Activity生命周期的事务类。(其实就像一个圣旨,AMS丢给应用程序,那么应用程序就必须执行这个圣旨)Activity主要使用其中6个(这里的6个是笔者在源码中明确看到调用setState来设置状态,其他的三种并未看到调用setState方法来设置状态,所以这里主要讲这6种),如下:
// Activity刚被创建时
public static final int ON_CREATE = 1;
// 执行完转到前台的最后准备工作
public static final int ON_START = 2;
// 执行完即将与用户交互的最后准备工作
// 此时该activity位于前台
public static final int ON_RESUME = 3;
// 用户离开,activity进入后台
public static final int ON_PAUSE = 4;
// activity不可见
public static final int ON_STOP = 5;
// 执行完被销毁前最后的准备工作
public static final int ON_DESTROY = 6;
状态之间的跳转不是随意的,例如不能从ON_CREATE
直接跳转到ON_PAUSE
状态,状态之间的跳转收到AMS的管理。当Activity在这些状态之间切换的时候,就会回调对应的生命周期。这里的状态看着很不好理解,笔者画了个图帮助理解一下:

这里按照「可交互」「可见」「可存在」三个维度来区分Activity的生命状态。可交互则为是否可以与用户操作;可见则为是否显示在屏幕上;可存在,则为该activity是否被系统杀死或者调用了finish方法。箭头的上方为进入对应状态会调用的方法。这里就先不展开讲每个状态之间的切换,主要是让读者可以更好地理解activity的状态与状态切换。
注意,这里使用的三个维度并不是非常严谨的,是结合总体的显示规则来进行区分的。
在谷歌的官方文档中对于
onStart
方法是这样描述的:onStart()
调用使 Activity 对用户可见,因为应用会为 Activity 进入前台并支持互动做准备。这也符合我们上面的维度的区分。而当activity进入ON_PAUSE状态的时候,Activity是可能依旧可见的,但是不可交互。如操作另一个应用的悬浮窗口的时候,当前应用的activity会进入ON_PAUSE状态。但是!在activity启动的流程中,直到onResume方法被调用,界面依旧是不可见的。这点在后面的源码分析再详细解释。所以这里的状态区分维度,仅仅只是总体上的一种区分,可以这么认为,但细节上并不是非常严谨的。需要读者注意一下。
生命周期的一个重要作用就是让activity在不同状态之间切换的时候,可以执行对应的逻辑。举个栗子。我们在界面A使用了相机资源,当我们切换到下个界面B的时候,那么界面A就必须释放相机资源,这样才不会导致界面B无法使用相机;而当我们切回界面A的时候,又希望界面A继续保持拥有相机资源的状态;那么我们就需要在界面不可见的时候释放相机资源,而在界面恢复的时候再次获取相机资源。每个Activity一般情况下可以认为是一个界面或者说,一个屏幕。当我们在界面之间进行导航切换的时候,其实就是在切换Activity。当界面在不同状态之间进行切换的时候,也就是Activity状态的切换,就会回调activity相关的方法。例如当界面不可见的时候会回调onStop
方法,恢复的时候会回调onReStart
方法等。
在合适的生命周期做合适的工作会让app变得更加有鲁棒性。避免当用户跳转别的app的时候发生崩溃、内存泄露、当用户切回来的时候失去进度、当用户旋转屏幕的时候失去进度或者崩溃等等。这些都需要我们对生命周期有一定的认知,才能在具体的场景下做出最正确的选择。
这一部分概述并没有展开讲生命周期,而是需要重点理解状态与状态之间的切换,生命周期的回调就发生在不同的状态之间的切换。我们学习生命周期的一个重要目的就是能够在对应的业务场景下做合适的工作,例如资源的申请、释放、存储、恢复,让app更加具有鲁棒性。
重要生命周期解析
关于Activity重要的生命周期回调方法谷歌官方有了一张非常重要的流程图,可以说是人人皆知。我在这张图上加上了一些常用的回调方法。这些方法严格上并不算Activity的生命周期,因为并没有涉及到状态的切换,但却在Activity的整个生命历程中发挥了非常大的作用,也是很重要的回调方法。方法很多,我们先看图,再一个个地解释。看具体方法解释的时候一定要结合下面这张图以及上一部分概述的图一起理解。

主要生命周期
首先我们先看到最重要的七个生命周期,这七个生命周期是严格意义上的生命周期,他符合状态切换这个关键定义。这部分内容建议结合概述部分的图一起理解。(onRestart并不涉及状态变换,但因为执行完他之后会马上执行onStart,所以也放在一起讲)
-
onCreate:当Activity创建实例完成,并调用attach方法赋值PhoneWindow、ContextImpl等属性之后,调用此方法。该方法在整个Activity生命周期内只会调用一次。调用该方法后Activity进入
ON_CREATE
状态。该方法是我们使用最频繁的一个回调方法。
我们需要在这个方法中初始化基础组件和视图。如viewmodel,textview。同时必须在该方法中调用setContentView来给activity设置布局。
这个方法接收一个参数,该参数保留之前状态的数据。如果是第一次启动,则该参数为空。该参数来自onSaveInstanceState存储的数据。只有当activity暂时销毁并且预期一定会被重新创建的时候才会被回调,如屏幕旋转、后台应用被销毁等
-
onStart:当Activity准备进入前台时会调用此方法。调用后Activity会进入
ON_START
状态。要注意理解这里的前台的意思。虽然谷歌文档中表示调用该方法之后activity可见,如下图:
但是我们前面讲到,**前台并不意味着Activity可见,只是表示activity处于活跃状态。**这也是谷歌文档里让我比较迷惑的地方之一。(事实上谷歌文档有挺多地方写的缺乏严谨,可能考虑到易懂性,就牺牲了一点严谨性吧)。