RXJava 全面学习笔记(下)

背压策略

  • 观察者&被观察者异步订阅,存在被观察者发送事件速度与观察者接受事件速度不匹配的情况, 主要发送事的事件速度>观察者接收事件速度
存在的问题
  • 被观察者发送事件速度太快,而观察者来不及接收所有事件,从而导致观察者无法及时响应/处理所有发送过来事件的问题,最终导致缓存区移除,事件丢失&OOM 如连续点击事件10次,只会造成2次的效果;
  • 由于被观察者发送事件速度>观察者接受事件速度,所以出现流速不匹配的问题,从而导致OOM
解决方案 背压策略
  • 定义 一种控制事件流速的策略

  • 作用:在异步订阅关系中,控制事件发送&接收的速度 内牙的作用域=异步订阅关系,即被观察者和观察者处于不同线程中,

  • 解决问题: 解决了因被观察者发送事件速度与观察者接收事件速度不匹配,从而导致观察者无法及时响应/处理所有被观察者发送事件的问题

  • 应用场景: 被观察者发送事件速度与观察者接收事件速度不匹配的场景

  • 具体场景就取决于该事件的类型:如网络请求,那么具体场景有很多网络请求需要执行,但是执行者的速度没有那么快,因此就需要背压策略来进行控制

  • 背压策略的原理:

    1. 避免出现事件发送和接收流速不匹配的情况(控制发送事件/接收事件的速度)
    2. 当出现事件发送&接收流速不匹配的解决方案(对超出缓存区大小的事件进行丢弃,保存,报错措施)
  • 采用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在功能的区别主要是多了背压的功能

      1545293768219

    • 控制观察者接收事件的速度

    • backpressureStratepy背压模式介绍

      • 作用:当缓存区大小存满后,被观察者任然继续发送下一个事件时,该如何处理的策略方式
      • 具体表现: 出现当缓存区大小存满(默认为128) 被观察者任然继续发送下一个事件时.
      • error 发送和接收流速不匹配 直接抛出MissingBackpressureException
      • missing 流速不匹配, 处理方式缓存区满了
      • buffer 流速不匹配. 处理方式, 将缓存区大小设置成无限大,注意内存情况 防止出现OOM
      • drop 流速不匹配,处理方式:超过缓存区大小(128)的事件丢弃
      • latest 流速不匹配 只保存最新(最后)事件,超过缓存区大小的事件丢弃
    • 特别注意:

      • 背景Flowable可通过自己创建, 或者通过其他方式自动创建,如Interval操作符

      • interval操作符: 每隔一段时间就产生一个数字,从0开始1一次增加1 直至无穷大,默认运行在1个新线程上,timer操作符可以结束发送

      • 冲突:

        • 对于自身手动创建的Flowable的情况, 可以通过传入背压模式参数选择背压策略
        • 对于自动创建的Flowable,却无法手动穿入被压参数,那么出现流速不匹配的情况,如何匹配呢?
      • 解决方案: Rxjava2内部封装了背压策略模式的方法,

        1. onBackpressureBuffer();
        2. onBackpressureDrop()
        3. onBackpressureLatest();
        4. 默认采用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"));
    
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值