背压:Flowable / Subscriber

  在RxJava 1.x 理解 中,没有讲到背压这个概念,是因为学习太落后了,RxJava都出2了,所以直接在2上学。  

  背压是下游控制上游流速的一种手段。在rxjava1.x的时代,上游会给下游set一个producer,下游通过producer向上游请求n个数据,这样上游就有记录下游请求了多少个数据,然后下游请求多少个上游就给多少个,这个就是背压。一般来讲,每个节点都有缓存,比如说缓存的大小是64,这个时候下游可以一次性向上游request 64个数据。rxjava1.x的有些操作符不支持背压,也就是说这些操作符不会给下游set一个producer,也就是上游根本不理会下游的请求,一直向下游丢数据,如果下游的缓存爆了,那么下游就会抛出MissingBackpressureException,也就是背压失效了。在rxjava2.x时代,上述的背压逻辑全部挪到Flowable里了,所以说Flowable支持背压。而2.x时代的Observable是没有背压的概念的,Observable如果来不及消费会死命的缓存直到OOM,所以rxjava2.x的官方文档里面有讲,大数据流用Flowable,小数据流用Observable。

经典教程:

同步线程_背压:

  /**
* 首先第一个同步的代码, 为什么上游发送第一个事件后下游就抛出了MissingBackpressureException异常,
* 这是因为下游没有调用request, 上游就认为下游没有处理事件的能力, 而这又是一个同步的订阅, 既然下游处理不了,
* 那上游不可能一直等待吧, 如果是这样, 万一这两根水管工作在主线程里, 界面不就卡死了吗, 因此只能抛个异常来提醒我们.
* 那如何解决这种情况呢, 很简单啦, 下游直接调用request(Long.MAX_VALUE)就行了,
* 或者根据上游发送事件的数量来request就行了, 比如这里request(3)就可以了.
*/
private void Backpressure_1() {
/**
* 首先是创建Flowable的时候增加了一个参数, 这个参数是用来选择背压,也就是出现上下游流速不均衡的时候应该怎么处理的办法,
* 这里我们直接用BackpressureStrategy.ERROR这种方式, 这种方式会在出现上下游流速不均衡的时候直接抛出一个异常,
* 这个异常就是著名的MissingBackpressureException. 其余的策略后面再来讲解.
*/
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);
}

结果:

异步线程_背压:

/**
* 然后我们再来看看第二段代码, 为什么上下游没有工作在同一个线程时,
* 上游却正确的发送了所有的事件呢?
* 这是因为在Flowable里默认有一个大小为128的水缸, 当上下游工作在不同的线程中时, 上游就会先把事件发送到这个水缸中,
* 因此, 下游虽然没有调用request, 但是上游在水缸中保存着这些事件, 只有当下游调用request时, 才从水缸里取出事件发给下游.
*/
private void Backpressure_2() {
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.
observeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(downstream);
}

背压策略:

  • BackpressureStrategy.ERROR : 默认缓存大小:128
  • BackpressureStrategy.BUFFER :缓存大小:无限
  • BackpressureStrategy.DROP :Drop就是直接把存不下的事件丢弃
  • BackpressureStrategy.LATEST :,Latest就是只保留最新的事件

RxJava给我们提供了其他的方法,加入背压:

  • onBackpressureBuffer()
  • onBackpressureDrop()
  • onBackpressureLatest()

private void Backpressure_5() {
Flowable
.create(new FlowableOnSubscribe<Integer>() {
@Override
public void subscribe(FlowableEmitter<Integer> emitter) throws Exception {
Log.d(TAG, "First requested = " + emitter.requested()); // 得知请求的量
boolean flag;
for (int i = 0; ; i++) {
flag = false;
while (emitter.requested() == 0) { // 判断是否发送数据
if (!flag) {
Log.d(TAG, "Oh no! I can't emit value!");
flag = true;
}
}
emitter.onNext(i);
Log.d(TAG, "emit " + i + " , requested = " + emitter.requested());
}
}
}, BackpressureStrategy.ERROR)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Subscriber<Integer>() {
@Override
public void onSubscribe(Subscription s) {
Log.d(TAG, "onSubscribe");
mSubscription = s;
//mSubscription.request(10);
} @Override
public void onNext(Integer integer) {
Log.d(TAG, "onNext:" + integer);
} @Override
public void onError(Throwable t) {
Log.d(TAG, "onError");
} @Override
public void onComplete() {
Log.d(TAG, "onComplete");
}
}); }
Subscription mSubscription;
Backpressure_5();
findViewById(R.id.button).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
mSubscription.request();
}
});

emitter.requested() == 0 就不创建新的数据。

参考资料:

这可能是最好的RxJava 2.x 教程(完结版)

RxJava 2.x 理解-3的更多相关文章

  1. RxJava 2.x 理解-1

    在RxJava 1.x 系列中,讲解了RxJava的大致用法,因为现在都用RxJava 2了,所以Rxjava 1就不细讲,主要来学习RxJava 2. 基本使用: /** * rajava2 的基本 ...

  2. RxJava 1.x 理解-3

    在 RxJava 1.x 理解-1 中,我们说到了RxJava的简单用法,但是这还远远不够,因为 输入的数据 ---> 被监听者(订阅源)对这些数据进行操作,或者执行响应的处理 --> 产 ...

  3. RxJava 1.x 理解-2

    给RxJava 加入线程控制 -- Scheduler 在 RxJava 1.x 理解-1 中,我们说到了RxJava的简单用法,但是这还远远不够,因为这简单用法是在同一个线程中使用的.比如我们需要在 ...

  4. RxJava 2.x 理解-2

    操作符总结: http://reactivex.io/documentation/operators.html https://github.com/ReactiveX/RxJava/wiki Ope ...

  5. RxJava 1.x 理解-1

    先看下别人实现的最基本的RxJava的实现方式: 在RxJava里面,有两个必不可少的角色:Subscriber(观察者) 和 Observable(订阅源). Subscriber(观察者) Sub ...

  6. RxJava+RxAndroid+MVP入坑实践(基础篇)

    转载请注明出处:http://www.blog.csdn.net/zhyxuexijava/article/details/51597230.com 前段时间看了MVP架构和RxJava,最近也在重构 ...

  7. 如何深入理解Java泛型

    一.泛型的作用与定义 1.1泛型的作用 使用泛型能写出更加灵活通用的代码泛型的设计主要参照了C++的模板,旨在能让人写出更加通用化,更加灵活的代码.模板/泛型代码,就好像做雕塑时的模板,有了模板,需要 ...

  8. 必读的 Android 文章

    必读的 Android 文章 掘金官方 关注 2017.06.07 13:58* 字数 25218 阅读 8782评论 2喜欢 218 写给 Android 开发者的混淆使用手册 - Android ...

  9. Android 使用Retrofit2.0+OkHttp3.0实现缓存处理+Cookie持久化第三方库

    1.Retrofit+OkHttp的缓存机制 1.1.第一点 在响应请求之后在 data/data/<包名>/cache 下建立一个response 文件夹,保存缓存数据. 1.2.第二点 ...

随机推荐

  1. 获取html元素内容

    html: <!DOCTYPE ><html> <head> <meta http-equiv="Content-Type" conten ...

  2. VC++中编译C出错:error C2143: syntax error : missing ';' before 'type'

    转摘自:http://preceo.blog.51cto.com/6225017/1130931 近来写程序时发现了一个问题,用 VC 编译 C语言是 总是提示一个错误:error C2143: sy ...

  3. JavaScript获取HTML元素样式的方法(style、currentStyle、getComputedStyle)

    一.style.currentStyle.getComputedStyle的区别 style只能获取元素的内联样式,内部样式和外部样式使用style是获取不到的. currentStyle可以弥补st ...

  4. 关于javascript中的this 一段小实例深有体会啊

    先声明鄙人正在努力的把脚抬进门来,说的都是比较粗浅的知识,但都是我实践中得出的体会,很深刻.  正在自学中挣扎的DOG. 先看段代码: function highlightRows() { if(!d ...

  5. Web应用程序开发,基于Ajax技术的JavaScript树形控件

    感谢http://www.cnblogs.com/dgrew/p/3181769.html#undefined 在Web应用程序开发领域,基于Ajax技术的JavaScript树形控件已经被广泛使用, ...

  6. RPC-Thrift(一)

    一个简单例子 IDL文件如下,详细的IDL语法参考官方文档http://thrift.apache.org/docs/idl. 通过代码生成工具得到两个文件:HelloService.java和Res ...

  7. WebComponents001

    Sample1: ShadowDom 隔离style,替换显示内容 <button>Hello, world!</button> <script> var host ...

  8. Linux 格式化磁盘命令mkfs

      linux格式化磁盘命令          mkfs        指令:mkfs 使用权限 : 超级使用者 使用方式 : mkfs [-V] [-t fstype] [fs-options] f ...

  9. 四维偏序(K-D-Tree+rebuild)

    其实只是放个代码,会K-D-Tree的同学看了就知道怎么rebuild了,其实也是很简单粗暴的…… 单独再发一次吧,感觉把代码跟之前的一起发不知道啥时候就找不到了…… #include<bits ...

  10. onchange监听input值变化及input隐藏后change事件不触发的原因与解决方法(设置readonly后onchange不起作用的解决方案)

    转自:https://www.cnblogs.com/white0710/p/7338456.html 1. onchange事件监听input值变化的使用方法: <input id=" ...