(6)RxJava2+Retrofit2+OkHttp3系列(RxJava2-6)
来源:互联网 发布:linux snmp起不来 编辑:程序博客网 时间:2024/05/22 07:00
上一节里我们学习了只使用Observable如何去解决上下游流速不均衡的问题,在这一节里我们先来学习如何使用Flowable。
正题
之前我们所的上游和下游分别是Observable和Observer, 这次不一样的是上游变成了Flowable, 下游变成了Subscriber, 但是水管之间的连接还是通过subscribe(), 我们来看看最基本的用法吧。
Flowable<Integer> upstream = Flowable.create(new FlowableOnSubscribe<Integer>() { @Override public void subscribe(FlowableEmitter<Integer> emitter) 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); //增加了一个参数 Subscriber<Integer> downstream = new Subscriber<Integer>() { @Override public void onSubscribe(Subscription s) { Log.d(TAG, "onSubscribe"); s.request(Long.MAX_VALUE); //注意这句代码 } @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"); } }; upstream.subscribe(downstream);//结果onSubscribe emit 1 onNext: 1 emit 2 onNext: 2 emit 3 onNext: 3 emit complete onComplete
我们注意到这次和Observable有些不同,首先是创建Flowable的时候增加了一个参数, 这个参数是用来选择背压,也就是出现上下游流速不均衡的时候应该怎么处理的办法, 这里我们直接用BackpressureStrategy.ERROR这种方式, 这种方式会在出现上下游流速不均衡的时候直接抛出一个异常,这个异常就是著名的MissingBackpressureException。
另外的一个区别是在下游的onSubscribe方法中传给我们的不再是Disposable了, 而是Subscription, 它俩有什么区别呢, 首先它们都是上下游中间的一个开关, 之前我们说调用Disposable.dispose()方法可以切断水管, 同样的调用Subscription.cancel()也可以切断水管, 不同的地方在于Subscription增加了一个void request(long n)方法, 这个方法有什么用呢?
我们将这句代码去除试试:
Flowable.create(new FlowableOnSubscribe<Integer>() { @Override public void subscribe(FlowableEmitter<Integer> emitter) 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).subscribe(new Subscriber<Integer>() { @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"); } });
这次我们取消掉了request这句代码, 来看看运行结果:
zlc.season.rxjava2demo D/TAG: onSubscribezlc.season.rxjava2demo D/TAG: emit 1zlc.season.rxjava2demo W/TAG: onError: io.reactivex.exceptions.MissingBackpressureException: create: could not emit value due to lack of requests at io.reactivex.internal.operators.flowable.FlowableCreate$ErrorAsyncEmitter.onOverflow(FlowableCreate.java:411) at io.reactivex.internal.operators.flowable.FlowableCreate$NoOverflowBaseAsyncEmitter.onNext(FlowableCreate.java:377) at zlc.season.rxjava2demo.demo.ChapterSeven$3.subscribe(ChapterSeven.java:77) at io.reactivex.internal.operators.flowable.FlowableCreate.subscribeActual(FlowableCreate.java:72) at io.reactivex.Flowable.subscribe(Flowable.java:12218) at zlc.season.rxjava2demo.demo.ChapterSeven.demo2(ChapterSeven.java:111) at zlc.season.rxjava2demo.MainActivity$2.onClick(MainActivity.java:36) at android.view.View.performClick(View.java:5637) at android.view.View$PerformClick.run(View.java:22429) at android.os.Handler.handleCallback(Handler.java:751) at android.os.Handler.dispatchMessage(Handler.java:95) at android.os.Looper.loop(Looper.java:154) at android.app.ActivityThread.main(ActivityThread.java:6119) at java.lang.reflect.Method.invoke(Native Method) at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:886) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:776)zlc.season.rxjava2demo D/TAG: emit 2zlc.season.rxjava2demo D/TAG: emit 3zlc.season.rxjava2demo D/TAG: emit complete
从运行结果中可以看到, 在上游发送第一个事件之后, 下游就抛出了一个著名的MissingBackpressureException异常, 并且下游没有收到任何其余的事件。可是这是一个同步的订阅呀, 上下游工作在同一个线程, 上游每发送一个事件应该会等待下游处理完了才会继续发事件啊, 不可能出现上下游流速不均衡的问题呀。
带着这个疑问, 我们再来看看异步的情况:
Flowable.create(new FlowableOnSubscribe<Integer>() { @Override public void subscribe(FlowableEmitter<Integer> emitter) 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<Integer>() { @Override public void onSubscribe(Subscription s) { Log.d(TAG, "onSubscribe"); mSubscription = 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"); } });//这次我们同样去掉了request这句代码, 但是让上下游工作在不同的线程onSubscribeemit 1emit 2emit 3emit complete
哎, 这次上游正确的发送了所有的事件, 但是下游一个事件也没有收到. 这是因为什么呢?
因为我们把request当做是一种能力, 当成下游处理事件的能力, 下游能处理几个就告诉上游我要几个, 这样只要上游根据下游的处理能力来决定发送多少事件, 就不会造成一窝蜂的发出一堆事件来, 从而导致OOM. 这也就完美的解决之前我们所学到的两种方式的缺陷, 过滤事件会导致事件丢失, 减速又可能导致性能损失. 而这种方式既解决了事件丢失的问题, 又解决了速度的问题。
学习了request, 我们就可以解释上面的两段同步和异步的代码了。
同步:为什么上游发送第一个事件后下游就抛出了MissingBackpressureException异常, 这是因为下游没有调用request, 上游就认为下游没有处理事件的能力, 而这又是一个同步的订阅, 既然下游处理不了, 那上游不可能一直等待吧, 如果是这样, 万一这两根水管工作在主线程里, 界面不就卡死了吗, 因此只能抛个异常来提醒我们。
异步:为什么上下游没有工作在同一个线程时, 上游却正确的发送了所有的事件呢? 这是因为在Flowable里默认有一个大小为128的水缸, 当上下游工作在不同的线程中时, 上游就会先把事件发送到这个水缸中, 因此, 下游虽然没有调用request, 但是上游在水缸中保存着这些事件, 只有当下游调用request时, 才从水缸里取出事件发给下游。
我们先来思考一下, 发送128个事件没有问题是因为FLowable内部有一个大小为128的水缸, 超过128就会装满溢出来。那既然你水缸这么小, 那我给你换一个大水缸如何:
Flowable.create(new FlowableOnSubscribe<Integer>() { @Override public void subscribe(FlowableEmitter<Integer> emitter) throws Exception { for (int i = 0; ; i++) { emitter.onNext(i); } } }, BackpressureStrategy.BUFFER).subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) .subscribe(new Subscriber<Integer>() { @Override public void onSubscribe(Subscription s) { Log.d(TAG, "onSubscribe"); mSubscription = 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"); } });
运行结果看图:
同样可以看到, 内存迅速增长, 直到最后抛出OOM。
我们在看看FLowable中剩下的两种策略:
- BackpressureStrategy.DROP:Drop就是直接把存不下的事件丢弃
- BackpressureStrategy.LATEST:,Latest就是只保留最新的事件
(1)我们先来看看BackpressureStrategy.DROP的实例。
public static void request() { mSubscription.request(128); }Flowable.create(new FlowableOnSubscribe<Integer>() { @Override public void subscribe(FlowableEmitter<Integer> emitter) throws Exception { for (int i = 0; i < 10000; i++) { //只发1w个事件 emitter.onNext(i); } } }, BackpressureStrategy.DROP).subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) .subscribe(new Subscriber<Integer>() { @Override public void onSubscribe(Subscription s) { Log.d(TAG, "onSubscribe"); mSubscription = s; s.request(128); //一开始就处理掉128个事件 } @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"); } });
这段代码上游只发送了10000个事件,下游在一开始就立马处理掉了128个事件,然后我们在外部再调用request(128)试试,一开始下游就处理掉了128个事件, 当我们再次request的时候, 只得到了第3317的事件, 后面的事件直接被抛弃。
(2)我们再来看看BackpressureStrategy.LATEST的实例。
public static void request() { mSubscription.request(128); }public static void demo4() { Flowable.create(new FlowableOnSubscribe<Integer>() { @Override public void subscribe(FlowableEmitter<Integer> emitter) throws Exception { for (int i = 0; i < 10000; i++) { //只发1w个事件 emitter.onNext(i); } } }, BackpressureStrategy.LATEST).subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) .subscribe(new Subscriber<Integer>() { @Override public void onSubscribe(Subscription s) { Log.d(TAG, "onSubscribe"); mSubscription = s; s.request(128); //一开始就处理掉128个事件 } @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个事件, 与Drop不同, Latest总是能获取到最后最新的事件, 例如这里我们总是能获得最后一个事件9999。
四种背压策略:
- BackpressureStrategy.ERROR
- BackpressureStrategy.BUFFER
- BackpressureStrategy.DROP
- BackpressureStrategy.LATEST
- (6)RxJava2+Retrofit2+OkHttp3系列(RxJava2-6)
- (1)RxJava2+Retrofit2+OkHttp3系列(RxJava2-1)
- (2)RxJava2+Retrofit2+OkHttp3系列(RxJava2-2)
- (3)RxJava2+Retrofit2+OkHttp3系列(RxJava2-3)
- (4)RxJava2+Retrofit2+OkHttp3系列(RxJava2-4)
- (5)RxJava2+Retrofit2+OkHttp3系列(RxJava2-5)
- (7)RxJava2+Retrofit2+OkHttp3系列(RxJava2-7)
- (9)RxJava2+Retrofit2+OkHttp3系列(OkHttp3-1)
- (8)RxJava2+Retrofit2+OkHttp3系列(Retrofit2-1)
- (10)RxJava2+Retrofit2+OkHttp3系列(综合案例)
- Retrofit2+OkHttp3+RxJava2
- Rxjava2+okhttp3+Retrofit2封装
- rxjava2 + retrofit2 + okhttp3遇到的问题
- RxJava2+Retrofit2+OkHttp3实现网络缓存
- RxJava2+Retrofit2导包(新)
- rxjava2 + retrofit2
- Retrofit2+RxJava2
- RxJava2+Retrofit2
- Windows 下Apache服务器搭建
- 初识UML
- maven-M2E及Extras的安装和使用
- 【基础】Unity Mesh(一) 初步使用Mesh画平面图形
- Linux系统安装android studio
- (6)RxJava2+Retrofit2+OkHttp3系列(RxJava2-6)
- position为fixed时设置z-index失效
- OpenCV 技术教程-人脸检测
- A Context-aware Attention Network for Interactive Question Answering--阅读笔记
- Spring Boot Mybatis 整合
- 数据库范式(1NF 2NF 3NF BCNF)
- 9基于opencv的图像金字塔_高斯金字塔_拉普拉斯金字塔与图片尺寸缩放
- 排序算法总结
- python除法:传统除法,真除法,floor除法