Rxjava2最全面的解析,面试突击版

此文的目的有三个: 1. 给对 RxJava2感兴趣的人一些入门的指引 2. 给正在使用 RxJava2但仍然心存疑惑的人一些更深入的解析 3.给想从RxJava1替换成RxJava2的人给出直接的对比。

RxJava概念介绍

RxJava=reactive+extension。 那么接下来我会分别对这两点进行整体的介绍。reactive又称reactive programming。也就是响应式编程。在往简单的说,rxjava可以很方便的处理线程切换的问题。说到这个,我们就会想到异步操作。handler?AsyncTask?但你要知道,随着请求的数量越来越多,代码逻辑将会变得越来越复杂。而rxjava却仍可以保持清晰的逻辑。它的原理就是创建一个Observable对象来搞事情。然后使用各种操作符通过建造者模式建立成一系列的链式操作。就如流水线一样,把事情搞完。然后发射给Observer进行处理。

观察者模式

rxjava的实现主要是通过观察者模式实现的。那么什么是观察者模式,我这边做一个简单的介绍。

栗子:观察者对被观察者进行一个简单,当被观察者被改变时,要立即做出反应。比如,你认为隔壁老王和你媳妇有一腿,但却没证据,此时,只要当隔壁老王进了你媳妇房门的时候,你就要去捕获他。在这个例子中,你是观察者,老王是被观察者。(记得当初我经常搞反了)。那么,观察者模式是否是一对一呢?很明显不是的,就上面的例子,你可以叫三千城管监听着老王。只要他有不轨之心。就打断他的第三条腿。也就是说多个观察者对应一个被观察者。字看累了来看图:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

其实在android中也有很多自带的观察者模式。最明显的莫过于点击事件。说个最简单的例子,点击按钮后弹一个吐司。那么,我们在点击按钮的时候,告知系统,此时,我需要弹一个吐司。那么就这么弹出来了。那么,这个时候问题来了。我是否需要实时去监听这个按钮呢?答案是不需要的。这就和前面的举例有的差距了。换句话说。我只要在此按钮进行点击时进行监听就可以了。这种操作被称为订阅。也就是说Button通过setOnClickListener对OnclickListener进行了订阅了操作,来监听onclick方法。

extension
  • 不仅支持事件序列,还支持数据流。事件–>动态的,无法预知,例如:事件点击,服务器的推送等等 数据流–>静态的,可预知的,例如:读取本地文件,播放音视频等等。

  • 通过操作符对中间事件的处理。

  • 线程操作的便捷。关于这些具体的实现。我会在后面一一举例。

RxJava1与RxJava2的区别

说到区别,可能有的小伙伴会问,我没看过rxjava1。可以直接看rxjava2么。个人觉得不必要,因为 rxjava2.x 是按照 Reactive-Streams specification 规范完全的重写的,完全独立于 rxjava1.x 而存在,它改变了以往 rxjava1的用法。换句话说,我学java需不需要先学C语言一样。

那么两者的区别体现在哪呢?主要是如下几个方面:

  • 空指针问题这应该是一个很大的变化,用过rxjava1的人都知道,我们可以在发射事件的时候传入NULL。但这在rxjava2中是不存在的。不信你试试?分分钟给你来一个NullPointerExpection。

  • Function相关的在rxjava1中,我们有各种Func1,Func2…,但在rxjava2中只有Function了。依旧记得看凯哥的文章的时候把我整蒙了。愣是没发现,后来才注意到被替换了。并且,他们都增加了throw exception。

  • 背压—backpressure 关于backpressure,这个就厉害了。厉害到我都不懂了。好了,开个玩笑,我们继续说。我们知道在Rxjava1中Observable对backpressure是支持的。但在Rxjava2中Observable取消了对backpressure的支持。并且引进了一个叫做Flowable的来支持backpressure。

那么什么是背压: 听不懂的含义:上游的生产速度大于下游的处理速度,导致下游处理不急,这种操作被称为backpressure。

这种情况看似很常见,但实际上,这种情况并不常见,或者可以说成非常罕见。那么遇到了怎么办?如果它出现了,直接丢弃。what the fuck?你tm在逗我?但事实就是这样,如果我们在开发过程中,遇到了backpressure,我们就应该丢弃它。

听得懂的含义:对于可丢弃的事件,上游生产速度过快导致事件堆积,当堆积到超出buffer上限的时候,就叫做backpressure。

处理方案是什么: 1、丢弃新事件;2、不丢弃,继续堆积。(忽略了backpressure,相当于Observable)。

适合backpressure的情况: 在线直播流:比如说,正在直播的时候,突然网络出现了卡顿,页面卡住了。那么当网络好了之后肯定不会是在接着之前的页面继续的,就相当于,你网络卡了多久,他就丢弃了多长时间的数据。

backpressure的关键点是什么:不可控,可丢弃。

基本使用

讲了一大堆理念知识,接下来就是开工干活了。那么关于Rxjava2的基本实现主要是三点:创建Observable,创建Observer,进行绑定。那么我们一个个的看。

创建Observable

Observable是什么?观察者还是被观察者?我又忘了。哈哈。开个玩笑,当然是后者了。为什么是先创建Observable而不是Observer?当然了,先后顺序的无所谓的。但是考虑到后面的链式调用。所以我这边就先写了先创建Observable了。

Observable observable = Observable.create(new ObservableOnSubscribe() {
@Override
public void subscribe(ObservableEmitter emitter) throws Exception {
emitter.onNext(“Hello”);
emitter.onNext(“Rxjava2”);
emitter.onNext(“My name is Silence”);
emitter.onNext(“What’s your name”);
//一旦调用onComplete,下面将不在接受事件
emitter.onComplete();
}
});

现在我来解释一下上面的ObservableEmitter到底是什么。字面意思是可观察的发射器。没错,这个就是被观察者用来发送事件的。它可以发出三种类型的事件,通过调用emitter的onNext(T value)、onError(Throwable error)和onComplete()就可以分别发出next事件、error事件和complete事件。至于这三个事件到底什么意思。不急,我们后面说。

创建Observer

现在我们来创建一个观察者,它决定了在观察中到底应该有着什么样的行为操作。

Observer observer = new Observer() {
@Override
public void onSubscribe(Disposable d) {
Log.i(TAG, "onSubscribe: " + d);
result += "onSubscribe: " + d + “\n”;
}

@Override
public void onNext(String string) {
Log.i(TAG, "onNext: " + string);
result += "onNext: " + string + “\n”;
}

@Override
public void onError(Throwable e) {
Log.i(TAG, "onError: " + e);
result += "onError: " + e + “\n”;
}

@Override
public void onComplete() {
Log.i(TAG, "onComplete: ");
result += "onComplete: " + “\n”;
}
};

其中onSubscribe、onNext、onError和onComplete是必要的实现方法,其含义如下:

  • onSubscribe:它会在事件还未发送之前被调用,可以用来做一些准备操作。而里面的Disposable则是用来切断上下游的关系的。

  • onNext:普通的事件。将要处理的事件添加到队列中。

  • onError:事件队列异常,在事件处理过程中出现异常情况时,此方法会被调用。同时队列将会终止,也就是不允许在有事件发出。

  • onComplete:事件队列完成。rxjava不仅把每个事件单独处理。而且会把他们当成一个队列。当不再有onNext事件发出时,需要触发onComplete方法作为完成标识。

进行Subscribe

订阅其实只需要一行代码就够了:

observerable.subscribe(Observer);

运行一个看看效果先:外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

和之前介绍的一样,先调用onSubscribe,然后走了onNext,最后以onComplete收尾。

神奇的操作符

对于rxjava来说,有一句话,我觉得说的很对,叫做:如果你每天研究一个操作符,最少一个半月,如果你想理解原理。最少半年。换句话说,有关rxjava的知识完全可以写一本书。那么本文肯定不会讲那么细。在这边我会给你们介绍一些常用的操作符。保证日常开发的流程足矣。

创建操作符

一般创建操作符是指,刚开始创建观察者的时候调用的。在基本使用中我已经介绍了create操作符,那么这边我们就要说到just,fromarray和interval了。

just

此操作符是将传入的参数依次发出来。

Observable observable = Observable.just(“Hello”, “Rxjava2”, “My name is Silence”,“What’s your name”);
// 将会依次调用:
// onNext(“Hello”);
// onNext(“Rxjava2”);
// onNext(“My name is Silence”);
// onNext(“What’s your name”);
// onCompleted();

fromarray

将传入的数组通过坐标一次发送出去。

String[] words = {“Hello”, “Rxjava2”, “My name is Silence”,“What’s your name”};
Observable observable = Observable.from(words);
// 将会依次调用:
// onNext(“Hello”);
// onNext(“Rxjava2”);
// onNext(“My name is Silence”);
// onNext(“What’s your name”);
// onCompleted();

interval

这个其实就是定时器,用了它你可以抛弃CountDownTimer了。现在我们看看怎么用:

Observable.interval(2, TimeUnit.SECONDS).subscribe(
new Consumer() {
@Override
public void accept(Long aLong) throws Exception {
Log.i(TAG, "accept: "+aLong.intValue());
}
}
);

我们看看结果:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

上面就是我们每隔2s打印一次long的值。

变换操作符

变换操作符的作用是对Observable发射的数据按照一定规则做一些变换操作,然后讲变换后的数据发射出去。变换操作符有map,flatMap,concatMap,switchMap,buffer,groupBy等等。这里我们会讲解最常用的map,flatMap、concatMap以及compose。

map

map操作符通过指定一个Function对象,将Observable转换为一个新的Observable对象并发射,观察者将收到新的Observable处理。直接上代码:

Observable.create(new ObservableOnSubscribe() {
@Override
public void subscribe(ObservableEmitter emitter) throws Exception {
emitter.onNext(1);
emitter.onNext(2);
emitter.onNext(3);
emitter.onNext(4);
}
}).map(new Function<Integer, String>() {
@Override
public String apply(Integer integer) throws Exception {
return “This is result " + integer + “\n”;
}
}).subscribe(new Consumer() {
@Override
public void accept(String str) throws Exception {
Log.i(”—>", "accept: "+str);
string += str;
}
});
tv_first.setText(string);

输入结果如下:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

仔细看,map()方法中,我们把一个integer对象转换成了一个String对象。然后当map()调用结束时,事件的参数类型也从integer转换成了String。这就是最常见的变换操作。

flatMap

flatmap的操作符是将Observable发射的数据集合变成一个Observable集合。也就是说它可以讲一个观察对象变换成多个观察对象,但是并不能保证事件的顺序。想保证事件的顺序?那你过会看下面降到的concatMap。

那么什么叫作数据集合变成一个Observable集合呢?还是用上面的例子,我有一组integer集合。我想转换成string集合怎么办?那就继续看代码:

Observable.create(new ObservableOnSubscribe() {
@Override
public void subscribe(ObservableEmitter emitter) throws Exception {
emitter.onNext(1);
emitter.onNext(2);
emitter.onNext(3);
}
}).flatMap(new Function<Integer, ObservableSource>() {
@Override
public ObservableSource apply(Integer integer) throws Exception {
final List list = new ArrayList<>();
for (int i = 0; i < 3; i++) {
list.add(“I am value " + integer + “\n”);
}
return Observable.fromIterable(list);
}
}).subscribe(new Consumer() {
@Override
public void accept(String s) throws Exception {
Log.i(”—>", "accept: "+s);
string += s;
}
});
tv_first.setText(string);

我们来看结果:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

打住打住,是不是有问题?WTF?有啥问题?还记不记得我上面说过flatMap不能保证事件执行顺序。那么这边事件为什么都是按顺序执行的?不急,我们在发射事件的时候给他加一个延迟在看看结果:

Observable.create(new ObservableOnSubscribe() {
@Override
public void subscribe(ObservableEmitter emitter) throws Exception {
emitter.onNext(1);
emitter.onNext(2);
emitter.onNext(3);
}
}).flatMap(new Function<Integer, ObservableSource>() {
@Override
public ObservableSource apply(Integer integer) throws Exception {
final List list = new ArrayList<>();
for (int i = 0; i < 3; i++) {
list.add(“I am value " + integer + “\n”);
}
return Observable.fromIterable(list).delay(100,TimeUnit.MILLISECONDS);
}
}).subscribe(new Consumer() {
@Override
public void accept(String s) throws Exception {
Log.i(”—>", "accept: "+s);
string += s;
}
});
tv_first.setText(string);

我们在当他发射事件的时候给他加一个100ms的延迟看看结果:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

看到没有,我说啥的?不能保证执行顺序。所以万事容我慢慢道来。先喝杯茶压压惊。我们在接着往下讲。

concatMap

上面我也介绍了concatMap。除了保证了执行顺序,其他都和concatMap一毛一样。你说保证就保证啊。您先喝杯茶,接着往下看:

Observable.create(new ObservableOnSubscribe() {
@Override
public void subscribe(ObservableEmitter emitter) throws Exception {
emitter.onNext(1);
emitter.onNext(2);
emitter.onNext(3);
}
}).concatMap(new Function<Integer, ObservableSource>() {
@Override
public ObservableSource apply(Integer integer) throws Exception {
final List list = new ArrayList<>();
for (int i = 0; i < 3; i++) {
list.add(“I am value " + integer + “\n”);
}
return Observable.fromIterable(list).delay(1000,TimeUnit.MILLISECONDS);
// return Observable.fromIterable(list);
}
}).subscribe(new Consumer() {
@Override
public void accept(String s) throws Exception {
Log.i(”—>", "accept: "+s);
string += s;
}
});
tv_first.setText(string);

为了我们能看的更明显一点,我这边直接设置了一秒钟的延迟。下面我们来看效果图:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

可以从执行顺序和打印时间看出,的的确确是延迟了一秒钟。

compose

这个操作符就很厉害了。他的变换是怎么做的呢?我们知道rxjava是通过建造者的模式通过链式来调用起来的。那么多个链式就需要多个Observable。而这个操作符就是把多个Observable转化成一个Observable。听起来是不是很厉害~。具体如何操作,我们接着看:


public ObservableTransformer<T, T> applyObservableAsync() {
return new ObservableTransformer<T, T>() {
@Override
public ObservableSource apply(Observable upstream) {
return upstream.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread());
}
};
}

自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数初中级安卓工程师,想要提升技能,往往是自己摸索成长,但自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年最新Android移动开发全套学习资料》送给大家,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
img
img
img
img

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频
如果你觉得这些内容对你有帮助,可以添加下面V无偿领取!(备注Android)
img

总结

算法知识点繁多,企业考察的题目千变万化,面对越来越近的“金九银十”,我给大家准备好了一套比较完善的学习方法,希望能帮助大家在有限的时间里尽可能系统快速的恶补算法,通过高效的学习来提高大家面试中算法模块的通过率。

这一套学习资料既有文字档也有视频,里面不仅仅有关键知识点的整理,还有案例的算法相关部分的讲解,可以帮助大家更好更全面的进行学习,二者搭配起来学习效果会更好。

部分资料展示:




有了这套学习资料,坚持刷题一周,你就会发现自己的算法知识体系有明显的完善,离大厂Offer的距离更加近。

资料获取方法:点赞+关注+转发,然后进入我的【GitHub】,里面有免费获取途径

还有案例的算法相关部分的讲解,可以帮助大家更好更全面的进行学习,二者搭配起来学习效果会更好。

部分资料展示:

[外链图片转存中…(img-kF2TKhv9-1711202434947)]
[外链图片转存中…(img-t9Bi6hs7-1711202434947)]
[外链图片转存中…(img-5YmGRYdK-1711202434947)]
[外链图片转存中…(img-FPjQCk2z-1711202434948)]

有了这套学习资料,坚持刷题一周,你就会发现自己的算法知识体系有明显的完善,离大厂Offer的距离更加近。

资料获取方法:点赞+关注+转发,然后进入我的【GitHub】,里面有免费获取途径

  • 20
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值