Rxjava原理探索:切换线程,变换

在之前的几篇博客中,我编写了一篇有关Rxjava学习笔记的,还有一个是RxJava使用示例(一): 实现Rxbus代替eventbus(这篇博文其实还不算完善,因为没有对被观察者发出的时间进行一个筛选,一次发送所有订阅者都会收到,这样不太好,可以再新加一个筛选器,等以后有空或者是遇到的时候再来改一改,现在不急)。

之前在写那边Rxjava学习笔记的时候,就突出了一点是只涉及使用,不涉及原理,现在就对Rxjava的原理进行一个简单的探索。

从整体来看

Rxjava属于一种扩展性的观察者模式,里面的四个基本概念是:Observable (可观察者,即被观察者)、 Observer (观察者)、 subscribe (订阅)、事件。Observable 和 Observer 通过 subscribe() 方法实现订阅关系,从而 Observable 可以在需要的时候发出事件来通知 Observer。

另外有一点是需要注意的,也是Rxjava很重要的一个特性,里面的onError方法,只要是发生错误的话就一定会被处理,所以可以将一些错误处理的代码直接写在onError中。

还有一点就是,Rxjava跟普通的观察者模式的区别在于如果observable没有任何Observer的话是不会发出任何事件的。

Observable负责在发生什么事件或者是订阅的对应条件产生时,就会发送事件去通知Observer,而具体的如何操作是有Observer接收到之后自己处理的,也就是说Observable只负责发,其余的处理由Observer自己来处理。

变化的原理

在Rxjava中存在flatMap以及Map,他们可以将一些指定的要发送的对象类型转换为另一个需要的对象类型,而这一个在Rxjava中是如何实现的呢?下面是我自己的一些理解,可能会有错误或偏差,欢迎指点。

// 这是摘自扔物线的精简后的lift代码
public <R> Observable<R> lift(Operator<? extends R, ? super T> operator) {
    return Observable.create(new OnSubscribe<R>() {
        @Override
        public void call(Subscriber subscriber) {
            Subscriber newSubscriber = operator.call(subscriber);
            newSubscriber.onStart();
            onSubscribe.call(newSubscriber);
        }
    });
}

代码中存在一个lift()方法,这个方法就是flatMap以及Map能够转换对象类型的关键。这里就只总结一下思路:
通过这个lift方法会创建一个新的observable,这个observable里面包含一个新的OnSubscribe,一个新的subscriber。

当用户调用经过 lift() 后的 Observable 的 subscribe() 的时候,使用的是新的 Observable
于是它所触发的 onSubscribe.call(subscriber),也是用的新 Observable 中的新
OnSubscribe。 而这个新 OnSubscribe 的 call() 方法中的 onSubscribe ,就是指的原始
Observable 中的原始 OnSubscribe ,在这个 call() 方法里,新 OnSubscribe 利用
operator.call(subscriber) 生成了一个新的 Subscriber(Operator 就是在这里,通过自己的
call() 方法将新 Subscriber 和原始 Subscriber 进行关联,并插入自己的『变换』代码以实现变换),然后利用这个新
Subscriber 向原始 Observable 进行订阅。

也就是说,原始的onSubscribe方法会发送数据发送到这个新的Subscriber中,而在这个新的Subscriber中会对数据进行一个处理,处理完成之后再发送给目标订阅者,也就是最原始的observer。而至于为什么要先发送数据到一个新的subscriber中,上面也提到过了,observable只管发,数据的处理是在subscriber中处理,这样分工明确。而当新的这个观察者处理完数据之后,再转发给原始的观察者。

线程切换

最开始我接触到Rxjava有三个原因:
第一个是代码的简洁度,链式。
第二个是响应式框架,观察者模式。
第三个就是它是一个异步的框架,线程切换功能极其强大,可任意指定观察者发生的线程以及被观察者的线程,随意调整极其强大(观察者发生的线程只能更改一次,被观察的可以随意切换)。

而之前也是一直都很好奇它的这个切换的流程是怎么样的,为什么只能观察者发生的线程只能更改一次而被观察的可以随意切换多次?

切换的流程

线程的切换其实也是使用了上面介绍到的lift方法,被观察者切换线程使用observeOn(),观察者切换线程使用subscriberOn(),可切换为多种线程,例如主线程,IO线程,新线程等等,具体的可以查看我的第一篇Rxjava博文,Rxjava学习笔记

observeOn()

在lift方法后,会创建一个新onSubscribe和一个新的subscriber。新的onSubscribe会通知原始的onSubscribe,原始的在收到通知后就会把信息发送到新的subscriber中,而这个时候如果设置了切换线程的话就会发生切换线程的操作

subscribeOn()
subscribeOn() 原理图

而subscribeOn()方法就不同了,它切换线程的位置是在新onSubscribe通知原始onSubscribe之前,这也就导致了如果设置了多个切换线程操作始终只有有第一个subscribeOn()方法切换成功,因为它切换线程是在整个的流程发生之前,而当第二个subscribeOn()方法调用时它已经是处于整个流程之中了,因此就无法设置多个。而observeOn()则不同,它的线程切换是发生在流程之中的,所以多个切换是被允许的。

疑问

总结到了这里,我产生了一个疑问,subscribeOn切换观察者的线程为什么要设置在整个流程之前而为什么observeOn方法会设置到整个流程之间?这个应该是创造者指定的一个规则吧,但是我很好奇为什么要这样设置。

————————————————— 更新
通过在stackOverFlow以及知乎上提问获得了想要的答案:

我的理解是subscribeOn是影响生产者(Observable)生产数据的线程的,通常我们只需要指定生产者在某一个特定的线程生产数据就可以满足我们的需求,至少我还没遇到过需要在生产数据的过程中去切换生产者所在的线程的情况。绝大多数我们需要变化线程的场景都是在数据生产之后,Rx里面就使用observeOn来指定各种operator和subcriber的线程,因为这些本质上都是数据的消费者。消费者可以任意切换自己接受处理数据的线程,足以满足我们的需求。
作者:hi大头鬼hi

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
RxJava 切换线程内存泄漏的原因可能有以下几点: 1. 订阅关系未正确取消:在使用RxJava进行线切换时,如果没有正确取消订阅关系,就可能导致内存泄漏。因为订阅关系会持有被观察者和观察者之间的引用,如果未及时取消订阅,就会导致观察者无法被释放,从而造成内存泄漏。 2. 使用错误的调度器:在RxJava中,切换线程需要使用Scheduler来指定要切换到的线程。如果使用了错误的调度器,可能导致线程资源无法正确释放,从而造成内存泄漏。 3. 长时间运行的任务:如果在使用RxJava进行线切换时,执行的任务是一个长时间运行的任务,可能会导致内存泄漏。因为长时间运行的任务可能会持有一些资源,如果没有及时释放这些资源,就会造成内存泄漏。 为避免RxJava切换线程内存泄漏,可以采取以下几个措施: 1. 及时取消订阅关系:在不需要继续观察的时候,及时取消订阅关系,可以使用CompositeDisposable来管理多个订阅关系,确保在不需要时能够正确取消订阅。 2. 使用正确的调度器:在进行线切换时,确保使用正确的调度器,比如使用Schedulers.io()进行IO操作,使用AndroidSchedulers.mainThread()进行主线程操作。 3. 避免长时间运行的任务:如果任务可能会持续较长时间,可以考虑使用takeUntil等操作符来限制任务的执行时间。 通过以上措施,可以有效避免RxJava切换线程内存泄漏的问题。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值