@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接口,观察者比较特殊,没有一个基础的包装类,而是直接封装了很多的包装类;
也是有100多个包装类;
那么到这里你是否会有疑惑,被观察者和观察者这么多的包装类,到底要咋用?
从上面的例子,可以知道,包装类是有一个过程的,有的是在创建的时候就进行包装了,而有的是在调用的时候进行包装的;
而RxJava的被观察者是在创建的时候进行包装的,比如上面的示例代码,第一步,通过Observable.create方法,里面通过创建ObservableCreate对象,进行了第一层的包装,此时的结构如下:
第二步的subscribeOn方法调用时,进行了第二层的包装,此时的结构如下:
第三步的observeOn方法调用时,进行了第四层的包装,那么结构就是下面这样样子:
最终调用订阅的方法的时候,已经进行了四次包装,可以这么理解,每调动一次操作符,那么就会进行一层被观察者的包装;
这样包装的好处是什么呢?
前面我们讲过,装饰者模式,是为了在不改变其原有的基础上,添加额外的功能;
这进行了这么几次包装的作用,就是为了添加额外的功能,那么来大概看一下每一层添加的额外功能有啥?
3.3、被观察者的subscribe方法
当我们最终调用了subscribe方法之后,我们会从最外层的包装类,一步一步的往里面调用;
上面我们知道,被观察者的包装,是在subscribeActual方法里,进行实现的,那么我们来看看这几个包装类的subscribeActual方法的逻辑;
先来看最外层的包装,来看一下subscribeActual大概的逻辑:
这里的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方法,执行了线程的切换,最终切换到主线程执行;
那么最终回调到这里之后,就是在主线程执行了;
最后
上面这些公司都是时下最受欢迎的互联网大厂,他们的职级、薪资、福利也都讲的差不多了,相信大家都是有梦想和野心的人,心里多少应该都有些想法。
也相信很多人也都在为即将到来的金九银十做准备,也有不少人的目标都是这些公司。
我这边有不少朋友都在这些厂工作,其中也有很多人担任过面试官,上面的资料也差不多都是从朋友那边打探来的。除了上面的信息,我这边还有这些大厂近年来的面试真题及解析,以及一些朋友出于兴趣和热爱一起整理的Android时下热门知识点的学习资料。
部分文件:
《Android学习笔记总结+移动架构视频+大厂面试真题+项目实战源码》,点击传送门,即可获取!
xt方法,上面我们知道这个方法只是做了判断,最终还是回调给上一层的包装类的onNext方法;
再上一层的包装类是SubscribeOnObserver,这个方法的onNext没有对观察者做任何处理;
那么还是得继续往上一层的包装类进行查看,上一层的包装类是ObserveOnObserver,这个类的onNext方法,执行了线程的切换,最终切换到主线程执行;
那么最终回调到这里之后,就是在主线程执行了;
最后
上面这些公司都是时下最受欢迎的互联网大厂,他们的职级、薪资、福利也都讲的差不多了,相信大家都是有梦想和野心的人,心里多少应该都有些想法。
也相信很多人也都在为即将到来的金九银十做准备,也有不少人的目标都是这些公司。
我这边有不少朋友都在这些厂工作,其中也有很多人担任过面试官,上面的资料也差不多都是从朋友那边打探来的。除了上面的信息,我这边还有这些大厂近年来的面试真题及解析,以及一些朋友出于兴趣和热爱一起整理的Android时下热门知识点的学习资料。
部分文件:
[外链图片转存中…(img-RYL8fpH5-1715594814583)]
[外链图片转存中…(img-FKaZuWZs-1715594814587)]
[外链图片转存中…(img-JCokrJj0-1715594814589)]
《Android学习笔记总结+移动架构视频+大厂面试真题+项目实战源码》,点击传送门,即可获取!