没错,没给你闹着玩,他真的又抛出大家喜欢的异常了,没毛病。
不知道,大家看完了RxJava1.0的背压,对它有什么看法?下面是我对RxJava1.0背压的一些理解
- 首先,RxJava1.0的背压事件缓存池很小,只有16,不能够处理较大量的并发事件。
- Rxjava1.0 中上游(被观察者)无法得知下游(观察者)对事件的处理能力和事件处理进度,只能把事件一股脑的抛给下游。
- Rxjava1.0有很多事件不被能正确的背压,从而抛出MissingBackpressureException
RxJava2.0
RXJava2.0中Observable不再支持背压,多出了Flowable来支持背压操作
既然说Observable不再支持背压,那么我们随便搞应该就不会报哪个MissingBackpressureException了吧?
Observable.create(new ObservableOnSubscribe() {
@Override
public void subscribe(ObservableEmitter emitter) throws Exception {
for (int i = 0; ; i++) { //无限循环发事件
emitter.onNext(i);
}
}
}).subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Consumer() {
@Override
public void accept(Integer integer) throws Exception {
Log.d(TAG, “” + integer);
}
});
上面的例子中我们创建了一个Observable(被观察者/上游)来发送无限循环的事件,观察者(下游)让下游来处理事件。
虽然说,不报异常了但是这内存也是看的我眼疼,崩溃也是正常现象啊,这么看来背压操作还是很有必要的啊,不然程序分分钟崩溃一次,怪我咯^&
如何解决阻塞
当然,提到如何解决阻塞问题吗,大家肯定会首先想到“背压”啊,好吧背压策略确实很神奇,但是它也不是万能的啊,你不了解也不能乱用啊,它也是哥,不要太迷信它
在上面的例子里,就上一个,不是其他的!在上面的例子里我们再RxJava2.0中是使用Observable一直发送死循环事件,由于下游没有任何背压策略,所以上游的每个事件,下游都要一一进行处理,所以程序的内存就一直开车,最后翻车也再说难免。
确实,是因为上游在短时间发送太多的事件,让下游来不及处理就造成了事件的阻塞,那么我们是否可以用一些自己的方法来解决这种阻塞呢?
使用背压啊!
“你妹的,说好的用自己的办法呢?”
首先,我们分析阻塞形成的原因,无非是因为下面的原因啊:
- 上游的水流过快(上游发送事件过快)
- 上游水流量过大(上游发送事件过多)
总结来说就是短时间发送的事件过多,下游忙不过来!
好吧,首先我们用第一种办法试下,让上游发送事件的速度慢点
//控制发送速度,减少内存消耗
Observable.create(new ObservableOnSubscribe() {
@Override
public void subscribe(ObservableEmitter emitter) throws Exception {
for (int i = 0; ; i++) { //无限循环发事件
emitter.onNext(i);
Thread.sleep(1000);
}
}
}).subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Consumer() {
@Override
public void accept(Integer integer) throws Exception {
Log.d(TAG, “” + integer);
}
});
这样来看,我的内存就稳定,老铁稳。
那么,试试第二种方法,下游少接收点事件
//定时取样
Observable.create(new ObservableOnSubscribe() {
@Override
public void subscribe(ObservableEmitter emitter) throws Exception {
for (int i = 0; ; i++) { //无限循环发事件
emitter.onNext(i);
}
}
}).sample(1, TimeUnit.SECONDS)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Consumer() {
@Override
public void accept(Integer integer) throws Exception {
Log.d(TAG, “” + integer);
}
});
或者是用过滤操作符,过滤掉一些上游事件
//过滤器 过滤操作
Observable.create(new ObservableOnSubscribe() {
@Override
public void subscribe(ObservableEmitter emitter) throws Exception {
for (int i = 0; ; i++) { //无限循环发事件
emitter.onNext(i);
}
}
}).filter(new Predicate() {
@Override
public boolean test(Integer integer) throws Exception {
return integer % 100 == 0;
}
})
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Consumer() {
@Override
public void accept(Integer integer) throws Exception {
Log.d(TAG, “” + integer);
}
});
背压策略
上面唠唠叨叨说了那么多,基本上也给大家阐明了阻塞形成的原因和解决阻塞的方法,基本策略就是减少发送事件的频率和减少发送事件的数量。
But……
我们手动让上游发送事件的速度满下来貌似是不可取的,你想让上游的速度十多快呢?上游需要等多久呢?
还有……
我们依旧无法知道下游处理事件的能力,无法很好地处理阻塞的事件。
当然,你们肯定会说RxJava2.0不是很好地支了背压了吗?是的,确实比较好地对阻塞做了处理,咱们来看下吧。
在RxJava2.0中官方,推出了Flowable 和Subscriber用来支持背压,同样的去除了Observable对背压的支持,对的就像你上面看到的,Observable不再支持背压了,即使阻塞崩溃也不会抛出MissingBackpressureException
还是上代码看看,Flowable的用法吧。
Flowable.create(FlowableOnSubscribe source, BackpressureStrategy mode)
创建Flowable会默认让传入一个FlowableOnSubscribe和一个BackpressureStrategy,FlowableOnSubscribe很好理解就是一个就是Flowable的一个被观察者源,而BackpressureStrategy就是Flowable提供的背压策略
有哪些策略还是上源码看下吧:
public enum BackpressureStrategy {
/**
- OnNext events are written without any buffering or dropping.
- Downstream has to deal with any overflow.
-
Useful when one applies one of the custom-parameter onBackpressureXXX operators.
/
MISSING,
/*
- Signals a MissingBackpressureException in case the downstream can’t keep up.
/
ERROR,
/* - Buffers all onNext values until the downstream consumes it.
/
BUFFER,
/* - Drops the most recent onNext value if the downstream can’t keep up.
/
DROP,
/* - Keeps only the latest onNext value, overwriting any previous value if the
- downstream can’t keep up.
*/
LATEST
}
MISSING:
如果流的速度无法保持同步,可能会抛出MissingBackpressureException或IllegalStateException。
BUFFER
上游不断的发出onNext请求,直到下游处理完,也就是和Observable一样了,缓存池无限大,最后直到程序崩溃
ERROR
会在下游跟不上速度时抛出MissingBackpressureException。
DROP
会在下游跟不上速度时把onNext的值丢弃。
LATEST
会一直保留最新的onNext的值,直到被下游消费掉。
先不看上面的策略,我们最起码先看看Flowable怎么用吧
Flowable.create(new FlowableOnSubscribe() {
@Override
public void subscribe(FlowableEmitter e) throws Exception {
Log.d(TAG, “emit 1”);
emitter.onNext(1);
Log.d(TAG, “emit 2”);
emitter.onNext(2);
Log.d(TAG, “emit 3”);
emitter.onNext(3);
Log.d(TAG, “emit complete”);
emitter.onComplete();
}
}, BackpressureStrategy.ERROR).subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Subscriber() {
@Override
public void onSubscribe(Subscription s) {
}
@Override
public void onNext(Integer s) {
Log.d(TAG, "onNext: " + integer);
}
@Override
public void onError(Throwable t) {
Log.d(TAG, “onError”+t);
}
@Override
public void onComplete() {
Log.d(TAG, “onComplete”);
}
});
上游 Flowable 构建FlowableEmitter用来发送上游事件,这里的背压策略我们采用ERROR,下游方法中出现了一个和原来
@Override
public void onSubscribe(Subscription s) {
}
Subscription.java
public interface Subscription {
public void request(long n);
public void cancel();
}
这里需要重点说明一下,在Flowable中背压采取拉取响应的方式来进行水流控制,也就是说Subscription是控制上下游水流的主要方式,一般的,我们需要调用Subscription.request()来传入一个下游目前能处理的事件的数量
那么,我们不传会怎么样?
备注:这里上下游是在不同的线程里进行的,如果在同一个线程里,它也会抛出一个MissingBackpressureException,让你去设置 调用request()方法
咦,我上游发送的事件,下游一个没收到啊
那么也就是说上游不能发射事件,是因为你没有调用request方法,因为你不调用request()上游不知道下游能处理事件的能力啊。
那么,也就是说我必须要调用request方法咯,那么我们就调用一下喽,官方说默认推荐使用Long.MAX_VALUE。
好吧,那么我们来试下吧,加上如下代码。
@Override
public void onSubscribe(Subscription s) {
s.request(Long.MAX_VALUE); //下游处理事件能力值
}
咦,还真正常了啊。
那么,我们设置个2试试?
s.request(2);
也就是说我们下游告诉上游我们能处理2个事件,这样上游就缓存池中取出了2个事件给发送给了下游。这点相比Rxjava1.0可以说是智能了很多,并不会一股脑的抛给下游而是又下游来主动拉取事件。
ERROR
Flowable既然可以跑了,那么咱们就来试试背压吧,我们还是采用BackpressureStrategy.ERROR这个策略,如果下游处理不过来就抛出异常。
Flowable.create(new FlowableOnSubscribe() {
@Override
public void subscribe(FlowableEmitter emitter) throws Exception {
for (int i = 0;i< 128; i++) {
Log.d(TAG, "emit " + i);
emitter.onNext(i);
}
}
}, BackpressureStrategy.ERROR).subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Subscriber() {
@Override
public void onSubscribe(Subscription s) {
Log.d(TAG, “onSubscribe”);
}
@Override
public void onNext(Integer integer) {
Log.d(TAG, "onNext: " + integer);
}
@Override
public void onError(Throwable t) {
Log.w(TAG, "onError: ", t);
}
@Override
public void onComplete() {
Log.d(TAG, “onComplete”);
}
});
我们,首先让上游发送128个事件,下游不做处理,恩好吧是正常的
现在我们把128改成129,怎么就异常了呢?
好吧,还是看源码吧
纳尼,原来Flowable的缓存池的最大大小是128吧,如果缓存池里有超过128个事件就会抛出异常,提示你去处理这些事件。
MISSING
那么,MISSING和ERROR有什么区别呢?
我们把缓存策略设置为BackpressureStrategy.MISSING试一下
Flowable.create(new FlowableOnSubscribe() {
@Override
public void subscribe(FlowableEmitter emitter) throws Exception {
for (int i = 0;i< 129; i++) {
Log.d(TAG, "emit " + i);
emitter.onNext(i);
}
}
}, BackpressureStrategy.MISSING).subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Subscriber() {
@Override
public void onSubscribe(Subscription s) {
Log.d(TAG, “onSubscribe”);
subscription = s;
}
@Override
public void onNext(Integer integer) {
Log.d(TAG, "onNext: " + integer);
}
@Override
public void onError(Throwable t) {
Log.w(TAG, "onError: ", t);
}
@Override
public void onComplete() {
Log.d(TAG, “onComplete”);
}
});
结构还是一样的,不过这次很友好的提示你队列满了
io.reactivex.exceptions.MissingBackpressureException: Queue is full?!
下面是MISSING策略的备注:
/**
- OnNext events are written without any buffering or dropping.
- Downstream has to deal with any overflow.
-
Useful when one applies one of the custom-parameter onBackpressureXXX operators.
*/
也就是说,这种策略是不丢弃,不缓存的策略,那么我要你也没什么用啊…………
BUFFER
BUFFER是一个无限大的缓存池,也就是说我们可以往里面存储无限多的事件
Flowable.create(new FlowableOnSubscribe() {
@Override
public void subscribe(FlowableEmitter emitter) throws Exception {
for (int i = 0;i<129 ; i++) {
Log.d(TAG, "emit " + i);
emitter.onNext(i);
}
}
}, BackpressureStrategy.BUFFER).subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Subscriber() {
@Override
public void onSubscribe(Subscription s) {
Log.d(TAG, “onSubscribe”);
}
@Override
public void onNext(Integer integer) {
Log.d(TAG, "onNext: " + integer);
}
@Override
public void onError(Throwable t) {
Log.w(TAG, "onError: ", t);
}
@Override
public void onComplete() {
Log.d(TAG, “onComplete”);
}
});
但是,如果我们发送无数多的事件,同样要注意内存情况。
DROP和LATEST
首先我们看下Drop
Flowable.create(new FlowableOnSubscribe() {
@Override
public void subscribe(FlowableEmitter emitter) throws Exception {
Log.d(TAG, "requested: " + emitter.requested());
for (int i = 0; ; i++) {
emitter.onNext(i);
}
}
}, BackpressureStrategy.DROP).subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Subscriber() {
自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。
深知大多数初中级Android工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则近万的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!
因此收集整理了一份《2024年Android移动开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Android开发知识点,真正体系化!
由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!
如果你觉得这些内容对你有帮助,可以扫码获取!!(备注:Android)
![](https://i-blog.csdnimg.cn/blog_migrate/396557918902d3815bc69d5f841985ec.jpeg)
Android开发除了flutter还有什么是必须掌握的吗?
相信大多数从事Android开发的朋友们越来越发现,找工作越来越难了,面试的要求越来越高了
除了基础扎实的java知识,数据结构算法,设计模式还要求会底层源码,NDK技术,性能调优,还有会些小程序和跨平台,比如说flutter,以思维脑图的方式展示在下图;
《互联网大厂面试真题解析、进阶开发核心学习笔记、全套讲解视频、实战项目源码讲义》点击传送门即可获取!
,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!**
如果你觉得这些内容对你有帮助,可以扫码获取!!(备注:Android)
![](https://i-blog.csdnimg.cn/blog_migrate/396557918902d3815bc69d5f841985ec.jpeg)
Android开发除了flutter还有什么是必须掌握的吗?
相信大多数从事Android开发的朋友们越来越发现,找工作越来越难了,面试的要求越来越高了
除了基础扎实的java知识,数据结构算法,设计模式还要求会底层源码,NDK技术,性能调优,还有会些小程序和跨平台,比如说flutter,以思维脑图的方式展示在下图;
[外链图片转存中…(img-OqswRCl1-1712672460859)]
《互联网大厂面试真题解析、进阶开发核心学习笔记、全套讲解视频、实战项目源码讲义》点击传送门即可获取!