前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >学着造轮子-RxLifeCycle

学着造轮子-RxLifeCycle

作者头像
三好码农
发布2018-09-11 10:52:46
7090
发布2018-09-11 10:52:46
举报
文章被收录于专栏:三好码农的三亩自留地

使用RxJava的一个很大的优势就是线程的灵活切换,特别是Android开发,工作线程请求,主线程监听,这已经是最普通的常规操作,但是Activity和Fragment都是有生命周期的,如何让我们的请求能在页面销毁时及时方便的撤销,可以说开发者的一个小小痛点。但是不想偷懒的码农不是三好码农,我将尝试逐步解决这个痛点,最后的结果可能还有优化的空间,重点是中间的思考过程。

一个常见的失败的例子

模拟Http请求,延迟10s后发射,不用多言

test_http_leak.png

在数据延迟结束前将Activity 关闭,这时候我们未做任何处理,结果自然是内存泄漏,因为我们的监听Consumer 在这里是一个匿名内部类,所以它会持有外部Activity 的引用,自然就泄漏了

memory_leak.png

问题发现了,我们就要想办法解决,第一个方法很容易想到,在Activity的onDestory方法中,判断任务是否被撤销,未撤销则执行撤销

Activity生命周期中撤销

dispose_on_destory.png

这样做确实可以,但是麻烦,而且不容易扩展,如果有多个请求,就要写多行dispose的代码,代码维护起来很痛苦,显然这个不是我们想要的。

尝试做抽象

我们的目标很明确,就是不需要Activity或者Fragment宿主持有Disposable对象去执行dispose方法,我们还是从RxJava的操作符中尝试找答案。

takeUtil

官方文档解释说明:“discard any items emitted by an Observable after a second Observable emits an item or terminates”,拙劣的翻译:“一个Observable丢弃掉所有发射的数据 在 第二个Observable发射了数据或者终止 之后”,看图解更直观

takeUtil.png

可以看到图中第二个Observable发射了数据0之后,第一个Observable之后发射的数据(从6开始)都被丢弃了,这个特性刚好非常适合我们的需求,通过第一个Observable A takeUtil 第二个Observable B,就可以通过给B发送数据 来达到终止A发射数据的需求。我们一般用Observable.create操作符创建的 Observable 都是在ObservableOnSubscriber中通过 emitter来发射数据,如果需要在外部发射数据,就需要利用新的对象Subject. RxJava 提供了 4种 Subject

  • AsyncSubject
  • BehaviorSubject
  • PublishSubject
  • ReplaySubject

我们重点说BehaviorSubject,它的特性是,最终发射的数据是在它被订阅之前发射的最后一条数据+被订阅后发射的所有数据,它能够保存一条被订阅前发射的最新一条数据,可以防止我们的异步请求漏掉activity或者fragment的生命周期。

compose

如果让我们的所有Observable都自己新建一个BehaviorSubject,然后去调用takeUtil,然后在activity或者Fragment的生命周期回调中调用 BehaviorSubject.onNext,这样就太麻烦,甚至比我们上面的第一种方法更繁琐,我们想到了compose操作符,它的作用就是对Observable进行一对一的转换,它的一个常规操作就是用来简化重复代码,比如SubscribeOn,ObserverOn 这样的公式代码, 当然我们在我们这里也可以用它,所以我们自然想到新建一个RxLifeCycleActivity基类,然后新建一个BehaviorSubject对象,新建一个bind方法,供子类调用绑定生命周期,然后在OnDestory中调用BehaviorSubject的onNext方法

RxLifeCycle act.png

然后在子类中就可以像这样调用来绑定生命周期

extend rxlifecycle act.png

对生命周期粒度进行细化

上面实现了请求在onDestory中一定会被终止,但是如果需求希望在onPause或者onStop中进行终止呢,所以 需要对生命周期事件进行细化,首先新建一个RxLifeCycleEvent枚举

event enum.png

然后在RxLifeCycleActivity中的生命周期回调用发送不同的事件

rxlifecycle event callback.png

然后新建一个新的方法bindUntil,第二个参数是想要终止的条件事件,我们对BehaviorSubject接收到的数据进行一次filter,发射条件是接收到的事件>终止的条件事件

bind until.png

更高的要求

这样我们的轮子算是一个能正常跑了,但是使用起来还是比较痛苦,因为要继承RxLifeCycleActivity类,而且还要实现一个RxLifeCycleFragment供 Fragment页面继承,这种改动的侵入性太强了。 这里可以参考Glide 图片下载的 生命周期监听的思路,给activity 或者 fragment 添加一个 空布局的RxLifeCycleFragment,然后将我们之前的RxLifeCycleActivity中的逻辑移植到这个fragment中,

RxLifeCycleFragment.png

然后新建一个门面类RxLifeCycle,添加bind(Activity activity) 方法和bindUtil(Activity activity, RxLifeCycleEvent event)方法

rxLifeCycle bind act.png

rxLifeCycle bind uitil act.png

这样我们的轮子基本就完成了,绑定fragment的代码大家可以看源码,毕竟水平有限,肯定还有很多优化的空间,最后附上项目地址

参考: 知乎 RxLifeCycle

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2018.08.14 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 一个常见的失败的例子
  • Activity生命周期中撤销
  • 尝试做抽象
    • takeUtil
      • compose
        • 对生命周期粒度进行细化
          • 更高的要求
          领券
          问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档