背压策略
- 观察者&被观察者异步订阅,存在被观察者发送事件速度与观察者接受事件速度不匹配的情况, 主要发送事的事件速度>观察者接收事件速度
存在的问题
- 被观察者发送事件速度太快,而观察者来不及接收所有事件,从而导致观察者无法及时响应/处理所有发送过来事件的问题,最终导致缓存区移除,事件丢失&OOM 如连续点击事件10次,只会造成2次的效果;
- 由于被观察者发送事件速度>观察者接受事件速度,所以出现流速不匹配的问题,从而导致OOM
解决方案 背压策略
-
定义 一种控制事件流速的策略
-
作用:在异步订阅关系中,控制事件发送&接收的速度 内牙的作用域=异步订阅关系,即被观察者和观察者处于不同线程中,
-
解决问题: 解决了因被观察者发送事件速度与观察者接收事件速度不匹配,从而导致观察者无法及时响应/处理所有被观察者发送事件的问题
-
应用场景: 被观察者发送事件速度与观察者接收事件速度不匹配的场景
-
具体场景就取决于该事件的类型:如网络请求,那么具体场景有很多网络请求需要执行,但是执行者的速度没有那么快,因此就需要背压策略来进行控制
-
背压策略的原理:
- 避免出现事件发送和接收流速不匹配的情况(控制发送事件/接收事件的速度)
- 当出现事件发送&接收流速不匹配的解决方案(对超出缓存区大小的事件进行丢弃,保存,报错措施)
-
采用Flowable实现背压策略
-
Flowable的基础使用非常类似于Observable
Flowable.create((FlowableOnSubscribe<Integer>) emitter -> { emitter.onNext(1); emitter.onNext(2); emitter.onNext(3); }, BackpressureStrategy.ERROR).subscribe(new FlowableSubscriber<Integer>() { @Override public void onSubscribe(Subscription s) { s.request(3); } @Override public void onNext(Integer integer) { Log.e(TAG, "接收到的数据为" + integer); } @Override public void onError(Throwable t) { Log.e(TAG, "出现异常"); } @Override public void onComplete() { } });
-
-
背压策略的使用
-
背压策略和Flowable的使用,
-
Flowable和Observable在功能的区别主要是多了背压的功能
-
控制观察者接收事件的速度
-
backpressureStratepy背压模式介绍
- 作用:当缓存区大小存满后,被观察者任然继续发送下一个事件时,该如何处理的策略方式
- 具体表现: 出现当缓存区大小存满(默认为128) 被观察者任然继续发送下一个事件时.
- error 发送和接收流速不匹配 直接抛出MissingBackpressureException
- missing 流速不匹配, 处理方式缓存区满了
- buffer 流速不匹配. 处理方式, 将缓存区大小设置成无限大,注意内存情况 防止出现OOM
- drop 流速不匹配,处理方式:超过缓存区大小(128)的事件丢弃
- latest 流速不匹配 只保存最新(最后)事件,超过缓存区大小的事件丢弃
-
特别注意:
-
背景Flowable可通过自己创建, 或者通过其他方式自动创建,如Interval操作符
-
interval操作符: 每隔一段时间就产生一个数字,从0开始1一次增加1 直至无穷大,默认运行在1个新线程上,timer操作符可以结束发送
-
冲突:
- 对于自身手动创建的Flowable的情况, 可以通过传入背压模式参数选择背压策略
- 对于自动创建的Flowable,却无法手动穿入被压参数,那么出现流速不匹配的情况,如何匹配呢?
-
解决方案: Rxjava2内部封装了背压策略模式的方法,
- onBackpressureBuffer();
- onBackpressureDrop()
- onBackpressureLatest();
- 默认采用onBackpressureStrategy.Error模式
Flowable.interval(1, TimeUnit.MILLISECONDS) .onBackpressureBuffer() // 添加背压策略封装好的方法,此处选择Buffer模式,即缓存区大小无限制 .observeOn(Schedulers.newThread()) .subscribe(new Subscriber<Long>() { @Override public void onSubscribe(Subscription s) { Log.d(TAG, "onSubscribe"); mSubscription = s; s.request(Long.MAX_VALUE); } @Override public void onNext(Long aLong) { Log.d(TAG, "onNext: " + aLong); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } } @Override public void onError(Throwable t) { Log.w(TAG, "onError: ", t); } @Override public void onComplete() { Log.d(TAG, "onComplete"); } });
-
-
retrofit结合RxJava的使用
-
retrofit之所以目前最热的网络请求框架,它是支持RxJava
-
二种方式在使用上最大的区别在于 传统方式采用Callback接口,而RxJava方式则用Observable接口,
- 用于描述网络请求的接口设置
- 网络请求的封装形式&发送形式
//retrofit方式:Call<..>接口形式 public interface GetRequest_Interface { @GET("url地址") Call<Translation> getCall(); // 注解里传入 网络请求 的部分URL地址 // getCall()是接受网络请求数据的方法 } // RxJava 方式:Observable<..>接口形式 @GET("url地址") public interface GetRequest_Interface { Observable<Translation> getCall(); /*******************请求的封装形式&发送形式不同**************************/ <-- retrofit方式 ->> // 1. 创建 网络请求接口 的实例 GetRequest_Interface request = retrofit.create(GetRequest_Interface.class); // 2. 采用Call<..>接口 对 发送请求 进行封装 Call<Translation> call = request.getCall(); // 3. 发送网络请求(异步) call.enqueue(new Callback<Translation>() { // 请求成功时回调 @Override public void onResponse(Call<Translation> call, Response<Translation> response) { ... } // 请求失败时回调 @Override public void onFailure(Call<Translation> call, Throwable throwable) { .... } }); <-- RxJava 版方式 ->> // 1. 创建 网络请求接口 的实例 GetRequest_Interface request = retrofit.create(GetRequest_Interface.class); // 2. 采用Observable<...>形式 对 网络请求 进行封装 Observable<Translation> observable = request.getCall(); // 3. 发送网络请求(异步) observable.subscribeOn(Schedulers.io()) // 在IO线程进行网络请求 .observeOn(AndroidSchedulers.mainThread()) // 回到主线程 处理请求结果 .subscribe(new Observer<Translation>() { // 发送请求后调用该复写方法(无论请求成功与否) @Override public void onSubscribe(Disposable d) { ...// 初始化工作 } // 发送请求成功后调用该复写方法 @Override public void onNext(Translation result) { ...// 对返回结果Translation类对象 进行处理 } // 发送请求成功后,先调用onNext()再调用该复写方法 @Override public void onComplete() { Log.d(TAG, "请求成功"); } // 发送请求失败后调用该复写方法 @Override public void onError(Throwable e) { Log.d(TAG, "请求失败"); } }); }
实例 注册成功后立即登录
Retrofit retrofit = new Retrofit.Builder().baseUrl("http://fy.iciba.com/") .addConverterFactory(GsonConverterFactory.create()) .addCallAdapterFactory(RxJava2CallAdapterFactory.create()).build(); Observable<Model> range1 = retrofit.create(API.class).getRange(); Observable<Model> range2 = retrofit.create(API.class).getRange2(); range1.subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) .doOnNext(model -> Log.e(TAG, model.toString())) .doOnError(throwable -> Log.e(TAG, "注册出错" + throwable.getMessage())) .observeOn(Schedulers.io()) .flatMap((Function<Model, ObservableSource<Model>>) model -> { Log.e(TAG, "执行成功后立即执行登录"); return range2; }) .observeOn(AndroidSchedulers.mainThread()) .subscribe(model -> Log.e(TAG, "登陆成功:" + model.toString()), throwable -> Log.e(TAG, "登录出错" + throwable.getMessage()), null, disposable -> Log.e(TAG, "disposable"));