Bask

Shanghai Based Android Engineer currently develop Payment systems at Ctrip

👨‍🔧‍

Android中组件生命周期完全解析

By Bask on May 06, 2018

This post is over a year old. Some of the content may be out of date.

一说到Android生命周期大家可能都会想到一个特别经典的图: 补图 看完可能大家都会似懂非懂知道什么叫做生命周期。但其实看完这个生命周期其实也只是了解Android中的“主要”生命周期部分。因为Android的生命周期并不仅仅包含这些。接下来想跟大家分享的是Android中生命周期一般处理方法是什么样的。

说到生命周期,主要有两大组件有生命周期--Activity,Fragment。之前还会有Dialog,但之后DialogFragment取代,而DialogFragment又是Fragment的子类。所以下面我们讨论的就是Activity和Fragment的生命周期。

生命周期控制器?要谈生命周期就不得不讨论一下生命周期是如何实现的。 Fragment的控制器我觉得大家都特别的熟悉,就是FragmentManager,FragmentManager类其实是一个抽象类,相关的实现方法都在FragmentManagerImpl中实现的。其中状态之间的切换都放在一个方法叫moveToState()方法中,有兴趣的同学可以研究下。大体逻辑我在这边说一下,分为两种情况:

  1. 现在的状态先于原Fragment状态
  2. 现在的状态晚于原Fragment状态 什么意思呢?什么叫先于,什么叫晚于呢?? 我们可以知道Fragment其实就是一个状态机,而他的状态的表现方法其实是Int的枚举类型。不同的状态分别由不同的Int值所代替。如果现在要改变的状态的值要变大,就说明现在的状态晚于原Fragment状态,如果小的话就是现在的状态先于原Fragment状态。 补图(代码缩略图) 接下来是moveToState()简单的流程图,便于大家的理解。 补图

既然Fragment都有生命周期控制器了,Activity没有岂不是很说不过去?所以某天我找了一下Activity的生命周期控制器,这个类的名字叫ActivityThread。他跟Fragment的实现方式不太一样。Activity的生命周期比Fragment的相对复杂一些。ActivityThread主要控制一些Activity的主要逻辑,比如启动Activity,重新启动Activity,停止Activity等。 补图 而这个控制器ActivityThread并不是直接控制Activity的,还封装了一层Instrumentation类,控制Activity的各个阶段需要做的事情。 补图

看完了相互之间独立的生命周期之后,我们需要了解一下Fragment与Activity之间的联动了。当Fragment依附于Activity之中的View时,Activity和Fragment的生命周期是怎样的?

首先得说一下既然Fragment依附于Activity。就说明Activity是控制Fragment的生命周期的。那通过什么控制呢?可以找到是通过FragmentController来控制FragmentManager进而控制Fragment生命周期的。相关我就不进行代码研读了,简单画一下Fragment与Activity交互的流程图吧 补图

最后我们看完了所有Android的生命周期的二三事,来解决一个Bug吧。 补Bug 初看这个Bug觉得会有一些不可思议,因为这是一个“偶现”Bug并不是所有进入这个Fragment的用户都会有空指针崩溃,但是理论上来说并不应该出现这样的空指针。但是为什么会出现呢? 我们来分析一下,空指针就是因为没有初始化,但是进入Fragment的时候肯定会初始化,为什么会没有初始化呢?只有一种可能性!!就是Activity在后台的时候被系统回收掉了。这样的问题常常会发生在APP之间相互跳转,比如分享、第三方支付等场景。进而内部变量都会变成null,如果调用的话肯定会爆空指针崩溃! 如何复现呢?这样的问题还是比较普遍的,总不能每次线上有问题了,才去解决吧。 在开发者选项中,有一个不保留用户活动,当勾时,每次进入下一个Activity的时候就会把上一个Activity销毁,返回上一个Activity时会重新创建。 知道了如何复现,就可以改Bug了。我们再来看下Activity的生命周期: 补图 当页面销毁的时候会进入onPause()、onStop()、onDestroy(),其实还有一个生命周期也会进入,就是onSaveInstanceState(Bundle outState)。重新创建的时候会走onRestoreInstanceState(Bundle savedInstanceState)所以我们只要搞清楚页面需求,将必要页面数据保存在onSaveInstanceState方法中,onRestoreInstanceState重新恢复就好。

附一个Demo