虽然RxJava的版本更新没有那么频繁,但是每次的更新,总会让人感觉,之前刚看的源码,是不是前功尽弃了😭,源码一更新,我又得继续去学习;
但是不知你是否有这样想过,框架一直在更新,底层有没有不变的东西,今天很高兴告诉你,RxJava框架有,那么这个不变的东西是什么呢?
架构
没错,RxJava虽然迭代了几个版本,但是其底层的架构还是没有怎么变动,为什么呢?因为其特性就决定了它的架构不会有多大的变化;
它的特性有哪些? 简单明了的代码逻辑,强大的操作符,而这些特性正是响应式编程的思想;
就好比一栋房子,其特性有抗震,防风,那么其底层的架构就是必然是按着抗震和防风的特性去建造的,而一旦建造成功,其具有的特性,不会跟着房子的装修而变化,那么其底层的架构也是同样的道理;
那么你想知道是什么架构来实现这种特性的吗?
别急,下面我们先来讲一讲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.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的包装类,非常强大,先看个图;
有一百多个包装类,由此可以看出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的包装类,非常强大,先看个图;
有一百多个包装类,由此可以看出RxJava的强大,当然也是装饰者模式给与其易扩展的特性;
上面看完被观察者的逻辑,下面来看看观察者的装饰者逻辑;
(2)观察者Observer:
-
第一步:要有一个抽象接口对应上面的Appearance接口,而RxJava的接口是Emitter和Observer,里面有好几个方法,基本一样,onNext,onError,onComplete,用于被观察者进行回调;
-
第二步:要有一个包装类,实现了Emitter或者Observer接口,观察者比较特殊,没有一个基础的包装类,而是直接封装了很多的包装类;
最后
其实Android开发的知识点就那么多,面试问来问去还是那么点东西。所以面试没有其他的诀窍,只看你对这些知识点准备的充分程度。so,出去面试时先看看自己复习到了哪个阶段就好。
上面分享的腾讯、头条、阿里、美团、字节跳动等公司2019-2021年的高频面试题,博主还把这些技术点整理成了视频和PDF(实际上比预期多花了不少精力),包含知识脉络 + 诸多细节,由于篇幅有限,上面只是以图片的形式给大家展示一部分。
【Android思维脑图(技能树)】
知识不体系?这里还有整理出来的Android进阶学习的思维脑图,给大家参考一个方向。
[外链图片转存中…(img-u9C5tF0y-1715873668363)]
【Android高级架构视频学习资源】
《Android学习笔记总结+移动架构视频+大厂面试真题+项目实战源码》,点击传送门,即可获取!