RxJava本质上不变的是什么?

虽然RxJava的版本更新没有那么频繁,但是每次的更新,总会让人感觉,之前刚看的源码,是不是前功尽弃了😭,源码一更新,我又得继续去学习;

但是不知你是否有这样想过,框架一直在更新,底层有没有不变的东西,今天很高兴告诉你,RxJava框架有,那么这个不变的东西是什么呢?

架构

没错,RxJava虽然迭代了几个版本,但是其底层的架构还是没有怎么变动,为什么呢?因为其特性就决定了它的架构不会有多大的变化;

它的特性有哪些? 简单明了的代码逻辑,强大的操作符,而这些特性正是响应式编程的思想;

就好比一栋房子,其特性有抗震,防风,那么其底层的架构就是必然是按着抗震和防风的特性去建造的,而一旦建造成功,其具有的特性,不会跟着房子的装修而变化,那么其底层的架构也是同样的道理;

那么你想知道是什么架构来实现这种特性的吗?

别急,下面我们先来讲一讲RxJava涉及到的设计模式,为什么设计模式这么重要呢?

因为设计模式是架构的基础,我们怎么设计才能让这个架构具有某种特性,这个和设计模式分不开;

2、RxJava的观察者模式


2.1、观察者模式

观察者模式,或许是我们最熟悉的设计模式,为什么呢?因为我们在代码里无时无刻都在使用着它;

它就是View的点击事件;

为什么说View的点击事件是观察者模式呢?下面我们先来看看观察者模式的定义;

定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知。

简单来说,就是被观察者与观察者之间存在着一对多的关系,一个被观察者可以被多个观察者依赖,当被观察者变化时,会通知到观察者;

而View的点击事件这里只是简单的一对一的关系,但是其实是可以实现一对多的关系;

而观察者模式的本质是当被观察者变化时,会通知到观察者,当View被点击的时候,会通过回调的监听通知到观察者,而观察者和被观察者之间存在订阅关系的时候,观察者才会被通知到;

而View的点击事件,是通过设置监听方法来实现订阅的,这就是我们最熟悉的观察者模式;

2.2、RxJava的观察者模式是怎样的呢?

RxJava的观察者模式,是扩展的观察者模式,为啥要叫扩展呢?因为它和普通的观察者模式不太一样,扩展的观察者模式,不止一个通知观察者的方法,它有好几个,下面我们来看看它的实现原理吧!

首先先来看一下RxJava观察者模式涉及到的几个类:

  • Observable:被观察者

  • Observer:观察者

  • Event:被观察者通知观察者的事件

  • Subscribe:订阅

看完下面这个图,你的心目中是不是已经对RxJava的观察者模式一目了然了;

下面我们来看一RxJava的事件类型,这个事件是被观察者用来通知观察者的,也就是Event,而Event可以分为下面几种类型,这个我们了解一下即可;

  • Next:常规事件,可以传递各种各样的数据;

  • Complete:结束事件,当观察者接收到结束事件后,就不会再接收后续被观察者发送来的事件;

  • Error:异常事件,当被观察者发送异常事件后,那么其他的事件就不会再继续发送了;

下面我用示例代码来讲一次RxJava的观察者模式;

首先定义一个观察者Observer:

public abstract class Observer {

// 和被观察者订阅后,会回调这个方法;

public abstract void onSubscribe(Emitter emitter);

// 传递常规事件,用于传递数据

public abstract void onNext(T t);

// 传递异常事件

public abstract void onError(Throwable e);

// 传递结束事件

public abstract void onComplete();

}

复制代码

Observer类的方法很简单,都是回调,这里有个新的接口类Emitter,这个Emitter是用来干嘛的呢?

我们暂且把这个Emitter称为发射器,主要用于发射事件;

public interface Emitter {

void onNext(T value);

void onError(Throwable error);

void onComplete();

}

复制代码

实现逻辑就是通过包装Observer,里面最终是通过Observer来进行调用的,来看看这个类有哪些方法;

public class CreateEmitter implements Emitter {

final Observer observer;

CreateEmitter(Observer observer) {

this.observer = observer;

}

@Override

public void onNext(T t) {

observer.onNext(t);

}

@Override

public void onError(Throwable error) {

observer.onError(error);

}

@Override

public void onComplete() {

observer.onComplete();

}

}

复制代码

里面的具体实现就是通过Observer对象来进行调用;

下面我们来看一下被观察者Observable是怎么实现的;

public abstract class Observable {

// 实现订阅的逻辑

public void subscribe(Observer observer){

// 通过将传进来的observer包装成CreateEmitter,用于回调

CreateEmitter emitter = new CreateEmitter(observer);

// 回调订阅成功的方法

observer.onSubscribe(emitter);

// 回调发射器emitter

subscribe(emitter);

}

// 订阅成功后,进行回调

public abstract void subscribe(Emitter emitter);

}

复制代码

这个类的逻辑很简单,就两步,第一步,进行订阅,第二步,回调Emitter对象,用于发射事件;

那么我们来看看怎么调用吧;

private void observer() {

// 第一步,创建被观察者

Observable observable = new Observable() {

@Override

public void subscribe(Emitter emitter) {

emitter.onNext(“第一次”);

emitter.onNext(“第二次”);

emitter.onNext(“第三次”);

emitter.onComplete();

}

};

// 第二步,创建观察者

Observer observer = new Observer() {

@Override

public void onSubscribe(Emitter emitter) {

Log.i(“TAG”, " onSubscribe ");

}

@Override

public void onNext(String s) {

Log.i(“TAG”, " onNext s:" + s);

}

@Override

public void onError(Throwable e) {

Log.i(“TAG”, " onError e:" + e.toString());

}

@Override

public void onComplete() {

Log.i(“TAG”, " onComplete ");

}

};

// 第三步,被观察者订阅观察者

observable.subscribe(observer);

}

复制代码

这里是使用逻辑很简单,分为三步:

  • 第一步:创建被观察者Observable;

  • 第二步:创建观察者Observer;

  • 第三步:被观察者Observable订阅Observer;

当订阅成功之后,被观察者的subscribe方法里面,就可以通过发射器发射各种事件,最终在观察者的方法里进行回调;

RxJava也是观察者和被观察者订阅的过程,只是被观察者有变化的时候,是通过发射器来发射各种事件的,这样就不局限于一种事件了;

3、RxJava的装饰者模式


3.1、装饰者模式

什么是装饰者模式?

要理解这个模式其实不难,我们从“装饰”这两个字就可以看出,这个模式用于装饰用的,至于怎么装饰,且听我细细道来;

比如说我现在有一个手机,我怎么在不改变这个手机原有的结构,而让其具有防摔的功能,当然你也可以说我的手机是诺基亚,从几楼往下丢,手机都不带磕碰的,但是现实是,我们使用的手机,并不是那么的抗摔;

那么我要怎么让其具有更强的抗摔能力呢?

相信答案你已经很清楚了,就是套手机壳,贴膜,而这两个动作,是在没有改变手机原有的结构上,让其具有了抗摔的功能,而这个过程可以称为装饰,而装饰者模式的原理也是如此;

在不改变其原有结构的基础上,为其添加额外的功能,是作为其原有结构的包装,这个过程称为装饰;

那么在代码里是怎么体现出来的呢?

同理,假如我们要在一个类上添加新功能,而不修改其原有的逻辑,那么我们这时候就可以使用装饰者模式进行封装,具体怎么做,我们下面来看看;

还是以上面为例子,定义一个外观的接口Appearance,有一个抽象的方法,结构structure;

public interface Appearance {

void structure();

}

复制代码

然后再定义一个手机类Phone实现这个接口,这个手机的结构有玻璃后盖,金属边框等属性,如下:

public class Phone implements Appearance {

@Override

public void structure() {

// 手机属性:玻璃后盖,金属边框

Log.i(“TAG”, “手机的属性:玻璃后盖,金属边框”);

}

}

复制代码

好了,接下来我们要让这个手机变得更坚固,但是又不能改变手机原有的结构,那么我们要怎么做呢?

如果不能修改其原有的结构,那么我可以通过装饰来对手机进行包装,先定义一个手机的包装类,用来包装手机,命名为PhoneDecorator,实现了Appearance接口,在这里通过构造方法传进来的外观类Appearance,调用了外观类的structure方法,保证其原有的功能实现;

简单来说,这个类的作用,就是为了实现原有类的功能;

public abstract class PhoneDecorator implements Appearance {

protected Appearance appearance;

public PhoneDecorator(Appearance appearance) {

this.appearance = appearance;

}

@Override

public void structure() {

appearance.structure();

}

}

复制代码

那么接下来就是包装类的具体实现了,定义一个套手机壳功能的类PhoneShell,功能实现就是在原有功能的基础上,给手机套上手机壳,来看看具体实现吧;

public class PhoneShell extends PhoneDecorator{

public PhoneShell(Appearance appearance) {

super(appearance);

}

@Override

public void structure() {

super.structure();

Log.i(“TAG”, “给手机套上手机壳”);

}

}

复制代码

这里的实现很简单,继承手机的包装类,在structure里面去实现“套上手机壳”的操作;

那么套手机壳的类有了,还差一个贴膜的类,和手机壳一样,我们也来定义一个贴膜的包装类PhoneCover,看看具体实现;

public class PhoneCover extends PhoneDecorator{

public PhoneCover(Appearance appearance) {

super(appearance);

}

@Override

public void structure() {

super.structure();

Log.i(“TAG”, “给手机贴上钢化膜”);

}

}

复制代码

这里的实现和上面的套手机壳的操作一样,那么到这里两个包装类都写好了,我们来看看怎么调用吧;

private void decorator() {

// 创建一个手机

Phone phone = new Phone();

// 给手机套上手机壳

PhoneShell phoneShell = new PhoneShell(phone);

// 给手机贴上钢化膜

PhoneCover phoneCover = new PhoneCover(phoneShell);

// 最终的手机结构

phoneCover.structure();

}

复制代码

使用起来很简单,将需要包装的类,作为构造参数,传入到包装类里面,就可以让这个类具有包装的功能,比如这里,将手机Phone传入到手机壳PhoneShell的类里面,那么手机就有套上手机壳的功能了;

同理,再将套上手机壳的手机PhoneShell类,传入到贴膜的类PhoneCover里面,那么这个手机就具有了贴膜的功能,最后再调用一下结构的方法structure,那么就可以看到这个手机已经被套上手机壳,并且贴上膜了;

最终包装后的结构如下:

到这里你有没有发现,装饰者对于功能的扩展并不是使用的继承的方法,为什么?

因为继承随着功能的增加,会导致子类越来越膨胀,而装饰者模式的双方可以随意扩展,不会相互耦合;

那么RxJava的装饰者模式是怎么实现的呢?

且听我细细道来;

3.2、RxJava的装饰者模式是怎么实现的呢?

RxJava的装饰者主要是用于实现被观察者Observable和观察者Observer的包装,为什么要进行包装呢?

从上面我们可以知道,装饰者模式,是基础功能上,不修改其原有的逻辑,进行扩展;

那么为什么RxJava的被观察者需要这种特性呢?

假如我想实现这样一种功能,在子线程获取数据,然后切换到主线程进行数据的赋值,正常情况下我们会这样做,先在子线程获取数据,然后再通过Handler的post方法,切到主线程;

但是如果我想在子线程获取到数据后,然后再对数据做一下转化处理,最后再回调给主线程呢?

如果按照常规的实现逻辑,这样的代码就会很混乱,作为一名有追求的工程师,我们是无法忍受这样的写法的;

那么有没有什么方式可以变的优雅一些呢?

答案是:有的;

RxJava通过装饰者模式+观察者模式设计出了链式调用的效果,这样代码逻辑清晰,也方便维护;

比如下面这样的链式调用逻辑:

Observable.create(new ObservableOnSubscribe() {

@Override

public void subscribe(@NonNull ObservableEmitter emitter) {

// 发射器发射数据

emitter.onNext(“1”);

emitter.onNext(“2”);

emitter.onNext(“3”);

emitter.onComplete();

}

}).subscribeOn(Schedulers.io())

.observeOn(AndroidSchedulers.mainThread())

.subscribe(new Observer() {

@Override

public void onSubscribe(@NonNull Disposable d) {

}

@Override

public void onNext(@NonNull Integer s) {

}

@Override

public void onError(@NonNull Throwable e) {

}

@Override

public void onComplete() {

}

});

复制代码

这样的链式调用逻辑是不是很清晰!

下面我们来看看RxJava的装饰者模式具体是怎么实现的;

我们以上面讲的手机模型为例子,来一步步拆解RxJava的装饰器模式;

(1) 被观察者Observable:

  • 第一步:要有一个抽象接口对应上面的Appearance接口,而RxJava的接口是ObservableSource,里面有一个方法,subscribe,用于和观察者进行订阅;

public interface ObservableSource {

/**

  • Subscribes the given Observer to this ObservableSource instance.

  • @param observer the Observer, not null

  • @throws NullPointerException if {@code observer} is null

*/

void subscribe(@NonNull Observer<? super T> observer);

}

复制代码

  • 第二步:要有一个包装类,实现了ObservableSource接口,对应上面的PhoneDecorator包装类,RxJava的包装类是Observable,和PhoneDecorator同理,实现了对应的接口,并且在subscribe方法里面通过调用抽象方法subscribeActual,来对观察者进行订阅;

public abstract class Observable implements ObservableSource {

@Override

public final void subscribe(Observer<? super T> observer) {

subscribeActual(observer);

}

protected abstract void subscribeActual(Observer<? super T> observer);

}

复制代码

  • 第三步:接下来就是具体的包装类了,和上面一样具有包装功能的PhoneShell,PhoneCover等等,而RxJava的包装类,非常强大,先看个图;

image

有一百多个包装类,由此可以看出RxJava的强大,当然也是装饰者模式给与其易扩展的特性;

上面看完被观察者的逻辑,下面来看看观察者的装饰者逻辑;

(2)观察者Observer:

  • 第一步:要有一个抽象接口对应上面的Appearance接口,而RxJava的接口是Emitter和Observer,里面有好几个方法,基本一样,onNext,onError,onComplete,用于被观察者进行回调;

  • 第二步:要有一个包装类,实现了Emitter或者Observer接口,观察者比较特殊,没有一个基础的包装类,而是直接封装了很多的包装类;

最后

其实Android开发的知识点就那么多,面试问来问去还是那么点东西。所以面试没有其他的诀窍,只看你对这些知识点准备的充分程度。so,出去面试时先看看自己复习到了哪个阶段就好。

上面分享的腾讯、头条、阿里、美团、字节跳动等公司2019-2021年的高频面试题,博主还把这些技术点整理成了视频和PDF(实际上比预期多花了不少精力),包含知识脉络 + 诸多细节,由于篇幅有限,上面只是以图片的形式给大家展示一部分。

【Android思维脑图(技能树)】

知识不体系?这里还有整理出来的Android进阶学习的思维脑图,给大家参考一个方向。

【Android高级架构视频学习资源】
《Android学习笔记总结+移动架构视频+大厂面试真题+项目实战源码》点击传送门,即可获取!
rver);

}

复制代码

  • 第三步:接下来就是具体的包装类了,和上面一样具有包装功能的PhoneShell,PhoneCover等等,而RxJava的包装类,非常强大,先看个图;

image

有一百多个包装类,由此可以看出RxJava的强大,当然也是装饰者模式给与其易扩展的特性;

上面看完被观察者的逻辑,下面来看看观察者的装饰者逻辑;

(2)观察者Observer:

  • 第一步:要有一个抽象接口对应上面的Appearance接口,而RxJava的接口是Emitter和Observer,里面有好几个方法,基本一样,onNext,onError,onComplete,用于被观察者进行回调;

  • 第二步:要有一个包装类,实现了Emitter或者Observer接口,观察者比较特殊,没有一个基础的包装类,而是直接封装了很多的包装类;

最后

其实Android开发的知识点就那么多,面试问来问去还是那么点东西。所以面试没有其他的诀窍,只看你对这些知识点准备的充分程度。so,出去面试时先看看自己复习到了哪个阶段就好。

上面分享的腾讯、头条、阿里、美团、字节跳动等公司2019-2021年的高频面试题,博主还把这些技术点整理成了视频和PDF(实际上比预期多花了不少精力),包含知识脉络 + 诸多细节,由于篇幅有限,上面只是以图片的形式给大家展示一部分。

【Android思维脑图(技能树)】

知识不体系?这里还有整理出来的Android进阶学习的思维脑图,给大家参考一个方向。

[外链图片转存中…(img-u9C5tF0y-1715873668363)]

【Android高级架构视频学习资源】
《Android学习笔记总结+移动架构视频+大厂面试真题+项目实战源码》点击传送门,即可获取!

  • 24
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值