RxJave内存泄漏解决方案之RxLifecycle笔记

    随着RxJava的热火与普及,他的缺点也逐渐被大家所发现。特别是在开发者使用不注意的时候,极容易造成内存泄漏。比如以下经典场景:使用RxJava发布一个订阅后,当Activity被finish,此时订阅逻辑还未完成,如果没有及时取消订阅,就会导致Activity无法被回收,从而引发内存泄漏。当然,也因此提出了好一些解决方案。其中有两种方案被大家所认可:

    1、通过进一步封装,手动在适当时机,取消订阅;

    2、监听所处活动(Aty/Frag)的生命周期,在特定的生命周期阶段进行取消订阅;

    目前,本人所采取的是方案1,因为本人采取的MVP模式,活动(Aty/Frag)主要进行View层的操作,这个方案的优点在于在原设计框架上,能够相对独立地在Presenter层进行处理以及个别订阅够比较灵活地进行订阅取消处理。缺点就是,过于依赖于开发者本身的主观意识,需要在每一次都进行手动处理。也因此,对于RxLifecycle进行了解,知道其采取的是方案2的原理,在了解过程中,看到好些大神在推荐AutoDispose,阅读了好些博客,觉得需要对其进行及时归纳,在此做一下笔记。

RxLifecycle基本

    具体的使用步骤,可以到官方或者网上查看一下,有很多,在此简单说明一下,不过多赘述。在引入相对应的库之后,需要在对应的Aty/Frag(推荐在BaseAty/BaseFrag中)继承其对应的封装的类。具体的操作步骤为:

    1、Activity/Fragment需继承RxAppCompatActivity/RxFragment;

    2、在订阅者中,compose操作符绑定容器生命周期(有两种方式,原理和操作地方都是一样的):

        2.1、使用bindToLifecycle()

        2.2、使用bindUntilEvent()

      如:// 当执行onDestory()时, 自动解除订阅

        Observable.interval(1, TimeUnit.SECONDS)

         .doOnDispose(newAction() {.... })                   

         .compose(this.bindToLifecycle()) //方式2:.compose(this.bindUntilEvent(ActivityEvent.DESTROY))

         .subscribe(newConsumer() {...  });

    原理解析

     上面我们说了,其最基础的原理是通过监听活动的生命周期,进行对订阅者的操作。那它的具体实现原理又是怎么样的呢?我们先看看源码的截图:

RxAppCompatActivity源码截图

        上图没有完全截取完,是在对应的周期回调方法内,进行相似的操作,可参考onStart与onResume方法体。我们可以看到,其里面主要是存储了一个BehaviorSubject 对象,而BehaviorSubject (释放订阅前最后一个数据和订阅后接收到的所有数据)其实本身也是一个发布者Observable。也就是在图中我们看到的那样,在对应的生命回调方法中进行对应的ActivityEvent的发送。

        从源码上看,我们也可以知道,bindToLifecycle()方法实际返回了一个LifecycleTransformer,LifecycleTransformer的作用,根据个人理解是将上游数据源进行拦截并对其进行执行takeUntil方法(有的博主说是实现了不同响应式数据类(Observable、Flowable等)的Transformer接口)。

    takeUntil操作符

    接下来就得看看takeUntil是干嘛用的了:当第二个Observable发射了一项数据或者终止时,丢弃原Observable发射的任何数据。到这里我们在看看原本的代码:

RxLifecycle实例代码截图

        可以看出,Activity.bindToLifecycle()实际上就是指定上游的数据源,当接收到某个Observable(就是LifecycleTransformer中那个神秘的成员变量)的某个事件时,该数据源自动解除订阅。

    到这里,我们就知道基本的流程了:当我们将其进行调用bindToLifecycle的时候,内部的会对这条订阅放入第二个发布者,而RxAppCompatActivity通过BehaviorSubject对象对应的生命回调接口会进行对应的消息发布,其再通过LifecycleTransformer里进行多种发布者的响应数据类,调取takeUntil,当第二个发布者发布信息的时候进行订阅解除。

    进一步探究

    如果只为了基本原理流程,到这里就可以结束了,但是为了探究一下,内部到底是怎么将第二个发布者放入这条订阅里面呢?或者说,BehaviorSubject对象发布的消息是怎么去驱动或者实现第二个发布者的操作呢?他们两个是不是同一个人?

    其实上文的BehaviorSubject对象就是我们所说的第二个发布者(也许在前头的说辞会造成你们的误解或者说明不清晰,我十分抱歉)。这也是前头,我们一直强调的,他本身也是一个发布者的原因。让我们看一下他里面重要的源码之一:

BehaviorSubject部分源码截图

    1、lifecycle.take(1)指的是最近发射的事件,比如说我们在onCreate()中执行了bindToLifecycle,那么lifecycle.take(1)指的就是ActivityEvent.CREATE,经过map(correspondingEvents),这个map中传的函数就是 1中的ACTIVITY_LIFECYCLE:

ACTIVITY_LIFECYCLE源码截图

    也就是说,lifecycle.take(1).map(correspondingEvents)实际上是返回了CREATE对应的事件DESTROY,它意味着本次订阅将在Activity的onDestory进行取消。

      2、lifecycle.skip(1)就简单了,除去第一个保留剩下的,以ActivityEvent.Create为例,这里就剩下:

            ActivityEvent.START、ActivityEvent.RESUME、ActivityEvent.PAUSE、ActivityEvent.STOP、ActivityEvent.DESTROY

      3、 第三个参数 意味着,lifecycle.take(1).map(correspondingEvents)的序列和 lifecycle.skip(1)进行combine,形成一个新的序列:

            false,false,fasle,false,true

            这意味着,当Activity走到onStart生命周期时,为false,这次订阅不会取消,直到onDestroy,为true,订阅取消。

       4、而后的onErrorReturn和filter是对异常的处理和判断是否应该结束订阅。

    至此,我们再总结一下整个RxLifecycle的原理流程:

    1.在Activity中,定义一个Observable(Subject),在不同的生命周期发射不同的事件;

    2.通过compose操作符(内部实际上还是依赖takeUntil操作符),定义了上游数据,当其接收到Subject的特定事件时,取消订阅;

    3.Subject的特定事件并非是ActivityEvent,而是简单的boolean,它已经内部通过combineLast操作符进行了对应的转化。

    以上内容,多数来自参考博客,如有异议或者参考博客本人禁止,请与本人联系!如有错误或者偏颇方面,希望批评指正,不胜感激!


参考博文:

---------------------

作者: 却把清梅嗅  来源:CSDN   题目:Android官方架构组件:Lifecycle详解&原理分析

链接:https://blog.csdn.net/mq2553299/article/details/79029657

---------------------

作者:不详  来源:红黑联盟   题目:RxLifecycle的使用及源码解读

链接:https://www.2cto.com/kf/201808/776242.html

你可能感兴趣的:(RxJave内存泄漏解决方案之RxLifecycle笔记)