RxJava本质上不变的是什么?(1)

@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接口,观察者比较特殊,没有一个基础的包装类,而是直接封装了很多的包装类;

也是有100多个包装类;

那么到这里你是否会有疑惑,被观察者和观察者这么多的包装类,到底要咋用?

从上面的例子,可以知道,包装类是有一个过程的,有的是在创建的时候就进行包装了,而有的是在调用的时候进行包装的;

而RxJava的被观察者是在创建的时候进行包装的,比如上面的示例代码,第一步,通过Observable.create方法,里面通过创建ObservableCreate对象,进行了第一层的包装,此时的结构如下:

第二步的subscribeOn方法调用时,进行了第二层的包装,此时的结构如下:

第三步的observeOn方法调用时,进行了第四层的包装,那么结构就是下面这样样子:

最终调用订阅的方法的时候,已经进行了四次包装,可以这么理解,每调动一次操作符,那么就会进行一层被观察者的包装;

这样包装的好处是什么呢?

前面我们讲过,装饰者模式,是为了在不改变其原有的基础上,添加额外的功能;

这进行了这么几次包装的作用,就是为了添加额外的功能,那么来大概看一下每一层添加的额外功能有啥?

3.3、被观察者的subscribe方法

当我们最终调用了subscribe方法之后,我们会从最外层的包装类,一步一步的往里面调用;

上面我们知道,被观察者的包装,是在subscribeActual方法里,进行实现的,那么我们来看看这几个包装类的subscribeActual方法的逻辑;

先来看最外层的包装,来看一下subscribeActual大概的逻辑:

image

这里的source是上一层包装类的实例,也就是ObservableSubscribeOn;

这里会将观察者进行一层包装,也就是ObserveOnObserver,这个ObserveOnObserver的包装,里面实现了线程切换的逻辑,具体逻辑在onNext里面;

为什么要这么做呢?因为这就是装饰者模式带来的好处,这个onNext的被观察者通知观察者会回调的方法,然后这里通过包装类,在里面实现了额外的线程切换的功能,这里会切换到主线程去执行;

此时,观察者的结构是这样的:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-W2ly565i-1613723791321)(https://upload-images.jianshu.io/upload_images/24957688-f349c58a6c1c5b8a.image?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)]

下面我们来看倒数第二层的包装类的subscribeActual方法的逻辑,倒数第二个包装类是ObservableSubscribeOn;

这一层包装类的subscribeActual方法又对观察者做了一层包装,也就是SubscribeOnObserver类,这个包装类又实现了什么功能呢?

这里做了一些线程的释放,这个我们下面再讲;

包装完之后观察者的结构是这样的:

让我们回到被观察者的实现逻辑,下面就调用了执行线程的方法,scheduleDirect,如果你传进来的是子线成的线程调度器Scheduler,那么SubscribeTask就会在子线程执行,而我们这里传的就是子线程;

在SubscribeTask,又调用了subscribe方法,这个source是上一层的包装类,也就是ObservableCreate,那么ObservableCreate的subscribeActual方法,就会在子线程执行了;

下面我们来看看ObservableCreate这个包装类的subscribeActual方法;

这里对观察者做了一层包装,也是CreateEmitter类,来看这个观察者的包装类又实现了什么额外的功能呢?

这里面主要实现了判断线程是否释放了,如果释放了,那么观察者就不再进行回调;

那么这时候,观察者的结构是这样的:

接下来就调用了观察者的onSubscribe方法,最终会回调到观察者Observer的onSubscribe方法;

然后下面就调用了source.subscribe(parent),这个source是我们创建的最原始的ObservableOnSubscribe,这里会回调到ObservableOnSubscribe的subscribe方法;

此时,我们上面的包装类ObservableSubscribeOn,切换到子线程后,那么我们的ObservableOnSubscribe的subscribe方法的执行也是在子线程;

3.4、被观察者通知观察者的事件是怎么流向的呢?

然后我们在ObservableOnSubscribe的subscribe方法里调用了发射器,发射字符串,那么这时候的调用逻辑是怎样的呢?

从上面观察者的结构来看,当发射器发送事件时,会一层层的回调对应的观察者包装类,从最外面一层开始;

上面我们知道ObservableEmitter类是CreateEmitter对观察者的包装,那么这个onNext就会走CreateEmitter的onNext方法,上面我们知道这个方法只是做了判断,最终还是回调给上一层的包装类的onNext方法;

再上一层的包装类是SubscribeOnObserver,这个方法的onNext没有对观察者做任何处理;

那么还是得继续往上一层的包装类进行查看,上一层的包装类是ObserveOnObserver,这个类的onNext方法,执行了线程的切换,最终切换到主线程执行;

那么最终回调到这里之后,就是在主线程执行了;

4、总结:

最后

上面这些公司都是时下最受欢迎的互联网大厂,他们的职级、薪资、福利也都讲的差不多了,相信大家都是有梦想和野心的人,心里多少应该都有些想法。

也相信很多人也都在为即将到来的金九银十做准备,也有不少人的目标都是这些公司。

我这边有不少朋友都在这些厂工作,其中也有很多人担任过面试官,上面的资料也差不多都是从朋友那边打探来的。除了上面的信息,我这边还有这些大厂近年来的面试真题及解析,以及一些朋友出于兴趣和热爱一起整理的Android时下热门知识点的学习资料

部分文件:



《Android学习笔记总结+移动架构视频+大厂面试真题+项目实战源码》点击传送门,即可获取!
xt方法,上面我们知道这个方法只是做了判断,最终还是回调给上一层的包装类的onNext方法;

再上一层的包装类是SubscribeOnObserver,这个方法的onNext没有对观察者做任何处理;

那么还是得继续往上一层的包装类进行查看,上一层的包装类是ObserveOnObserver,这个类的onNext方法,执行了线程的切换,最终切换到主线程执行;

那么最终回调到这里之后,就是在主线程执行了;

4、总结:

最后

上面这些公司都是时下最受欢迎的互联网大厂,他们的职级、薪资、福利也都讲的差不多了,相信大家都是有梦想和野心的人,心里多少应该都有些想法。

也相信很多人也都在为即将到来的金九银十做准备,也有不少人的目标都是这些公司。

我这边有不少朋友都在这些厂工作,其中也有很多人担任过面试官,上面的资料也差不多都是从朋友那边打探来的。除了上面的信息,我这边还有这些大厂近年来的面试真题及解析,以及一些朋友出于兴趣和热爱一起整理的Android时下热门知识点的学习资料

部分文件:
[外链图片转存中…(img-I8wzIgrd-1715873631504)]
[外链图片转存中…(img-0HNp3zV6-1715873631506)]
[外链图片转存中…(img-8Vru7GHn-1715873631507)]
《Android学习笔记总结+移动架构视频+大厂面试真题+项目实战源码》点击传送门,即可获取!

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值