不看lifecycle源码,认真聊聊它的实现原理

Posted microhex

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了不看lifecycle源码,认真聊聊它的实现原理相关的知识,希望对你有一定的参考价值。

1. lifecycle 简介

  在我们的日常开发中,使用ActivityFragment 产生的内存泄漏问题比比皆是,主要是原因就是这二者存在生命周期,在走完这一辈子的过程中,有些引用一直抓着着ActivityFragment不放,等到它们Destroy的时候,依旧引用着它们的尸体,导致不能被回收,因为尸体将一直存在于内存中,导致可用内存减少,然后内存泄漏就开始了。当然了,扯远了,Google废了那么大的劲儿开发了 Jetpack系列,主要是的原因是为了广大开发者能够写出高质量、高性能的代码,今天这里要说的 lifecycle 就是其中的一个优秀代表了。

那么lifecycle 到底有什么用呢?举个很朴实无华的例子,在MVP架构大行其道时,我们的Presenter层经常需要感知V层(即Activity或者Fragment)的生命周期,在对应的生命周期回调中做些操作,比如在 onDestory中取消网络请求,关闭数据库等等操作。我们一般的做法是在Activity 的基类中持有 Presenter的基类,重写Activity的生命周期回调函数,并在这些回调中调用Presenter的相应生命周期方法。但是有些组件可能传入的参数并非是Activity,无法传入一个预定义的类在Activity相应的生命周期中调用。因为Google提供了LifeCycle组件,用于向一个Activity/Fragment注册生命周期的回调监听。

之所以Google提供了这种方式,其实就是为了方便开发者无需重写Activity的生命周期回调方法,直接使用观察者模式对其生命周期进行监听回调。同时Lifecycle中没有Activity/Fragment的引用,因此不存在内存泄漏问题。

说了这么多,可能你都没心情看下去,或者一脸懵逼,先来个例子我们试试吧。

2. lifecycle 用法

首先build.gradle

    implementation "androidx.lifecycle:lifecycle-extensions:2.2.0"
    implementation 'androidx.lifecycle:lifecycle-runtime-ktx:2.2.0'
    implementation 'androidx.lifecycle:lifecycle-common-java8:2.2.0'

首先定义一个类继承自androidx.lifecycle.LifecycleObserver :

class MyCustomObserverBeforeJava8 : LifecycleObserver {
    
    @OnLifecycleEvent(Lifecycle.Event.ON_CREATE)
    fun onCreateX() {
        Log.d(TAG,"MyCustomObserver onCreate")
    }

    @OnLifecycleEvent(Lifecycle.Event.ON_START)
    fun onStart(owner : LifecycleOwner) {
        Log.d(TAG,"MyCustomObserver onStart : $owner")
    }

    @OnLifecycleEvent(Lifecycle.Event.ON_ANY)
    fun onResume(owner : LifecycleOwner, event : Lifecycle.Event) {
        Log.d(TAG,"MyCustomObserver onAny, $owner, $event")
    }

    @OnLifecycleEvent(Lifecycle.Event.ON_DESTROY)
    fun onDestroy() {
        Log.d(TAG,"MyCustomObserver onDestroy")
    }

    companion object {
        private val TAG : String = 	MyCustomObserverBeforeJava8::class.java.simpleName
    }
}

注意到我们的每一个方法上面都有一个注解@OnLifecycleEvent ,注解上面都存在一个Lifecycle.Event事件,一般都能猜到,被 Lifecycle.Event.ON_CREATE修饰的方法是在 Activity#onCreate() 方法之后调用的的,依次类推,Lifecycle.Event.ON_STARLifecycle.Event.ON_DESTROY等等就不说了,如果不是特别的懂,可以使用代码调试调试:

写好了生命周期监听逻辑,剩下的就是去找我们的Activity建立联系了:


class MyCustomUI : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        Log.d(TAG," onCreate method")
    }

    override fun onStart() {
        super.onStart()
        Log.d(TAG," onStart method")

    }

    override fun onResume() {
        super.onResume()
        Log.d(TAG," onResume method")

        lifecycle.addObserver(MyCustomObserverBeforeJava8())
    }

    override fun onDestroy() {
        Log.d(TAG,"onDestroy method")

        super.onDestroy()
    }
    
    companion object {
        private val TAG = MyCustomUI::class.java.simpleName

    }
}

看一下,就是这么简单,lifecycle来自androidx.activity.mLifecycleRegistry,然后就注册了,我们把MyCustomUI启动起来:


由于我是在Activity#onResume方法中注册的,因此输出也应该是这样的:先走完Activity#onCreate() onStart() onResume()然后再执行 我监听MyCustomObserverBeforeJava8中的 onCreate() onStart() 方法,可能这个比较神奇,或者有违背于我们的思想。我们被拉进了一个新的微信群,按照道理说,我应该看不到我没加入之前的聊天信息,我是在onResume方法中注册的,Activity的onCreate()、onStart() 应该在我注册之前就已经被执行过了,理论上我是不应该去接受的,但是这个比较奇怪,也算是lifeCycle 中比较奇怪实现方式了,其实它也有一个书面名字叫“倒灌”,这里我们就不重点讨论了,今天的目的是简单的去了解它,理解它的基本原理即可。

3. lifecycle 原理

看了上面的例子,也许你会和我当初想法类似,为啥加个注解就能感知Activity或者Fragment的生命周期啊,我都没没有重写过Activity 的生命周期方法啊,它是怎么做到的呢?我们先不去扒源码,想想在lifecycle之前,我们所使用过的源码中,是否也有过类似的实现方式呢?

了解Glide的人肯定都知道,Glide也可以监听Activity或者Fragment的生命周期,这是因为Glidewith 的时候,添加了一个 空白无界面的SupportRequestManagerFragment,然后通过监听这个SupportRequestManagerFragment的生命周期方法,从而来监听ImageView所在的 Activity 的动作变化,从而在各个生命周期中进行ImageView的请求和销毁。

那我们可以打印一下我们的 MyCustomUI中存在的fragments:

override fun onResume() {
        super.onResume()
     
        supportFragmentManager.fragments.forEach { Log.d(TAG, "current fragment : $it") }
        
    }

打印结果:

这里存在一个ReportFragment ,看吧,天下代码都是相互借鉴的,我估计Google 在开发lifecycle时或多或少应该借鉴了Glide内置一个无界面 Fragment的思想,那么我们就来看看这个ReportFragment在干嘛什么吧:

public class ReportFragment extends Fragment {
   private static final String REPORT_FRAGMENT_TAG = "androidx.lifecycle"
                    + ".LifecycleDispatcher.report_fragment_tag";

   @Override
   public void onActivityCreated(Bundle savedInstanceState) {
        super.onActivityCreated(savedInstanceState);
        dispatch(Lifecycle.Event.ON_CREATE);
   }

  @Override
  public void onStart() {
       super.onStart();
    	dispatch(Lifecycle.Event.ON_START);
 }

 @Override
 public void onResume() {
    super.onResume();
    dispatch(Lifecycle.Event.ON_RESUME);
 }

 @Override
 public void onPause() {
   super.onPause();
   dispatch(Lifecycle.Event.ON_PAUSE);
 }

 @Override
 public void onStop() {
    super.onStop();
    dispatch(Lifecycle.Event.ON_STOP);
}

@Override
public void onDestroy() {
     super.onDestroy();
    dispatch(Lifecycle.Event.ON_DESTROY);
  
 }
}

正与我们所料,它并没有重写Activity的生命周期方法,但是它重写了Fragment的生命周期方法,然后通过这个dispatch方法将生命周期事件分发出去。到此我们的大方向思路就非常明确了,lifecycle是通过内置的ReportFrament来监听生命周期,并将生命周期方法回调分发出去。

其实到了这里,你大概就理解了lifecycle的工作原理了,出去面试的时候,说到这里如果感觉没啥说的,那么就可以往下看,因为思路虽然简单,但是理解起来还是比较费劲的,可能是Google 的源码工程师写的代码比较深入精髓,想要完全去理解还是需要花一些功夫的。

这里我也不带大家去看源码了,这里我想要自己的语言来描述一下这个过程。

人生中我们会经历出生、幼儿期、儿童期、青年期、中年期、老年期、死亡这一系列的周期,同样我们经常使用的Activity也会经历创建,onCreate,onStart,onResume,onPause,onStoponDestroy等生命周期,走完这一短暂又精彩的一生,我们可以看到一张非常经典的Activity生命周期图

与人生不可逆的状态相比,Activity可以重复很多次onStart(),onResume(),onPause()onStop()。如果我们把Activityresume比作人最壮年的时期,那么从onCreate() -> onStart()->onResume()可以看作成一个状态上升;从onResume()-> onPause() -> onStop()可以看作成状态下降,类似于下面的这张图:

首先我们需要明白的一点是,当我们的Activity执行的某个生命周期方法,只是其生命周期中的一个时间点,而不是时间段。因此在LifeCycle源码中,把Activity的整个生命周期分成了7个时间段:

  1. 从被创建到调用onCreate()之间的时间段,称之为INITIALIZED;
  2. onCreate()之后,到onStart()之前的时间段,称之为CREATED;
  3. onStart()之后,到onResume()之前的时间段,称之为STARTED;
  4. Activity调用了onResume(),可以说是一瞬间的事件单,称之为RESUMED;
  5. onResume()之后,到onPause()之前,为了节省资源和逻辑,Google也把这个状态称之为STARTED;
  6. onPause()之后,到onStop()之前,同时也是为节省资源,Google也把这个状态称之为CREATED;
  7. 最后一种状态,从onStop()之后,到onDestroy()之前,称之为DESTROYED.

为了便于运算,我们需要将5State进行大小排序:

DESTROYED < INITIALIZED < CREATED < STARTED < RESUMED

理解了上述的前提知识,我们现在需要弄清楚这样一个逻辑,在ReportFragment的各个生命周期事件中,是如何通过dispatch不同的Event,比如

  1. Lifecycle.Event.ON_CREATE,
  2. Lifecycle.Event.ON_START,
  3. Lifecycle.Event.ON_RESUME,
  4. Lifecycle.Event.ON_PAUSE,
  5. Lifecycle.Event.ON_STOP,
  6. Lifecycle.Event.ON_DESTROY

来通知注册的LifecycleObserver, 从而执行自定义LifecycleObserver中对应的生命周期方法。
大体的意思可以参考下图:

这里就不卖关子了,直接看LifeCycle源码怎么做了。
上面我们说过,Activity的生命周期可以分开两部分去看,一部分是从construct到onResume()的过程,可以理解为由弱变强的过程,上上图曲线斜率一直为正的过程;另外一个部分是由onResume()到OnDestory()的过程,可以理解为有强变弱的过程,上上图斜率一直为负的过程。

LifeCycle源码中,也是按照这个想法分成两个过程的,上升和下降,它有一个很重要的方法叫getStateAfter(Event),位于androidx.lifecycle.LifecycleRegistry#getStateAfter()下,大概的意思就是按照ReportFragment分发的LifeCycle.Event, 来确定当前注册的LifecycleObserver应该确定在什么周期范围内。

这个getStateAfter方法的源码就不贴了,直接贴张图了解一下其意思:
对于上升趋势的LifeCycle.Event:

具体怎么理解呢?
ReportFragment分发的一个Lifecycle.Event.ON_CREATE事件,这时候注册的LifecycleObserver们的生命周期State需要到CREATED阶段; 同样Lifecycle.Event.ON_START事件,LifecycleObserver们的生命周期State需要到STATED; 最后分发ON_RESUME事件,LifecycleObserver们的生命周期的State需要到RESUME.

同理,对于下降趋势的LifeCycle.Event,也有相应的图对应:

大致原理和上图差不多,就不细说了。

然后两张图拼接在一起:

按照上面的这张图,我再次把逻辑说一遍,也许第一次看上次会觉得比较乱,但是多体会体会,会觉得LifeCycle的源码真的写的很艺术:

ReportFragment会在特定的生命周期方法内分发一个LifeCycle.Event事件,然后这个事件会在LifecycleRegistry这个类中被转化成State状态,然后LifecycleRegistry会分发给注册的LifecycleObserver,更新每一个LifecycleObserver中指向的State值,使得所有的LifecycleObserver#State同步,从而达到LifecycleObserver监听LifeCycleOwner的生命周期的目的。

当然还有更加细节的逻辑,可能没有讲到,主要是画图我就感觉头晕脑胀了。当然,你看这个图时候,其实每条都有其特殊的意义,upEvent和downEvent不仅仅包含了LifeCycle.Event转化为State的逻辑,同时也包含了State生成LifeCycle.Event的行为。

什么意思呢?
举个例子,在upEvent的逻辑中,如果我得知当前的StateCREATED状态的,那么下一个事件将要指向为LifeCycle.Event.ON_START事件。这个是干什么用的呢?不扯淡了,就是执行对应注解@OnLifecycleEvent(Lifecycle.Event.ON_START)修饰的方法使用的,这里有时间再写篇文章聊聊这个问题吧。

对于LifeCycle的原理,基本上也算是讲了一遍,没有非常深入的讨论源码,因为我认为每个人读源码深入程度都不一样,而且对的源码讲原理也会枯燥和无味,那么我就用自己所理解的语言写出来。当然,这也算是自己的理解,肯定会非常的粗糙和混乱,希望大家可以指出。

以上是关于不看lifecycle源码,认真聊聊它的实现原理的主要内容,如果未能解决你的问题,请参考以下文章

Android Lifecycle实现原理

Android Lifecycle实现原理

Android Lifecycle实现原理

Android arch components 源码分析—— Lifecycle

「Spring 」「AOP 容器」不看源码就带你认识核心流程以及运作原理

认认真真的聊聊“软“中断