Rxjava详解

  1. Rxjava的优点:
  • 链式调用,代码调用流程异常清晰 ,代码简洁。
  • RxJava和EventBus一样也是基于观察者模式,但是使用的场景确实异步数据流的处理
  • RxJava更加强大,利用操作符它可以对发出的消息进行一系列的变换
  1. 引入依赖:
compile 'io.reactivex.rxjava2:rxjava:2.0.1'
       compile 'io.reactivex.rxjava2:rxandroid:2.0.1'
  1. RxJava到底是什么?
    Rxjava的是通过一种扩展的观察者设计模式来实现异步操作,跟AsyncTask和Handler类似,但是比AsyncTask和Handler更加简洁随着程序逻辑变得越来越复杂,它依然能够保持逻辑的简洁。
  2. 基本实现
    (1) 创建观察者Observer,它决定事件触发的时候该有的行为。
private Observer<String> observer = new Observer<String>() {
            @Override
            public void onSubscribe(Disposable d) {
                //RxJava 2.0 中新增的,传递参数为Disposable ,Disposable 相当于1.x中的Subscription,调用d.dispose()解除绑定
            }

            @Override
            public void onNext(String value) {

            }

            @Override
            public void onError(Throwable e) {
                //在事件处理过程中出异常时,onError()会被触发
            }

            @Override
            public void onComplete() {
                //事件队列完结时调用该方法
            }
        };
(2) 创建被观察者Observable,它决定什么时候以及怎样触发事件
Observable observable = Observable.create(new ObservableOnSubscribe<String>() {
                @Override
                public void subscribe(ObservableEmitter<String> e) throws Exception {
                    e.onNext("A");
                    e.onNext("B");
                    //onError和onComplete()只能调用其中一个
                    e.onComplete();
                }
    });

Observable的其他创建方式

//just方式创建
    Observable<String> observable = Observable.just("Hello","A");
//fromIterable()用于集合数据,fromArray()用于数组数据方式,
    List<String> array1=new ArrayList<>();
    array1.add("F");
    array1.add("G");
    Observable.fromIterable(array1).subscribe(observer);
//创建一个按固定时间间隔发射整数序列的Observable,可用作定时器。即按照固定2秒一次调用onNext()方法。
    Observable<Long> interval = Observable.interval(2, TimeUnit.SECONDS);

(3) 订阅

//创建了 Observable 和 Observer 之后,再用 subscribe() 方法将它们联结起来
    //被观察者订阅观察者,符合流式代码的结构
    mObservable.subscribe(observer);
(5) 简洁的写法:
String[] word= new String[]{"hello", "world", "chinses"};
        Disposable subscribe = Observable.fromAray(word).subscribe(new Consumer<String>() {
                @Override
                public void accept(String aLong) throws Exception {
                    //相当于Observer的onNext()
                    Log.i(TAG, "accept: " + aLong);
                }
            }, new Consumer<Throwable>() {
                @Override
                public void accept(Throwable throwable) throws Exception {
                    //相当于Observer的onError()
                    Log.i(TAG, "onError: ");
                }
            }, new Action() {
                @Override
                public void run() throws Exception {
                    //相当于Observer的onComplete()
                    Log.i(TAG, "onComplete: ");
                }
            });

        subscribe.dispose();//取消订阅
另外我们需要明白两点:
1.Observable和Observer可以做任何事情
   Observable可以是一个数据库查询,Observer用来显示查询结果(传递数据);Observable可以是屏幕上的点击事件,
   Observer用来响应点击事件(传递事件);Observable可以是一个网络请求,Observer用来显示请求结果。

2.Observable和Observer是独立于中间的变换过程的。
   在Observable和Observer中间可以增减任何数量的操作符。整个系统是高度可组合的,操作数据是一个很简单的过程
  1. 操作符:
    作用:将事件序列中的对象或整个序列进行加工处理,转换层不同的事件或事件序列
  • filter() :可以对Observable流程的数据进行一层过滤处理,返回一个新的Observable,filter()返回为false的值将不会发出到Subscriber。
Observable.just("A").map(new Function<String, Integer>() {
                @Override
                public Integer apply(String s) throws Exception {
                    return s.length();
                }
            }).filter(new Predicate<Integer>() {
                @Override
                public boolean test(Integer integer) throws Exception {
                    return integer != 10;
                }
            }).subscribe(new Consumer<Integer>() {
                @Override
                public void accept(Integer integer) throws Exception {
                    Log.i(TAG, "accept: " + integer);
                }
            });
  • map(): 事件对象的直接变换,一个Observable对象上可以多次使用map操作符
Observable.just("images/logo.png") // 输入类型 String
     .map(new Function<String, Bitmap>() {
         @Override
         public Bitmap apply(String filePath) { // 参数类型 String
             return getBitmapFromPath(filePath); // 返回类型 Bitmap
         }
     }).subscribe(new Consumer<Bitmap>() {
                @Override
                public void accept(Bitmap bitmap) throws Exception {
                    showBitmap(bitmap);
                }
     });
  • flatMap():flatMap() 和 map() 有一个相同点:它也是把传入的参数转化之后返回另一个对象,不同的是, flatMap() 中返回的是个 Observable 对象。
//有方法根据输入的字符串返回一个List集合信息
     Observable<List<String>> query(String text); 
     //假如不用flatMap()我们应该这样写:
       query("message")
      .subscribe(new Function<List<String>>() {
            @Override
            public void apply(List<String> mLists) {

               Observable.fromIterable(mLists)  
               .subscribe(new Consumer<String>() {
                @Override
                public void accept(String message) {
                      log.i(TAG,message);           
                }
             });      
          }
      });
使用flatMap()这样写:
query("Hello, world!")  
    .flatMap(new Function<List<String>, Observable<String>>() {  
        @Override  
        public Observable<String> apply(List<String> urls) {  
            return Observable.from(urls);  
        }  
    })  
    .subscribe(new Consumer<String>() {
                @Override
                public void accept(String message) {
                      log.i(TAG,message);           
                }
    });

扩展:嵌套的异步请求,第一个网络请求获取第二个网络请求所需要的参数

networkClient.token() // 返回 Observable<String>,在订阅时请求 token,并在响应后发送 token
        .flatMap(new Function<String, Observable<Messages>>() {
            @Override
            public Observable<Messages> apply(String token) {
                // 返回 Observable<Messages>,在订阅时请求消息列表,并在响应后发送请求到的消息列表
                return networkClient.messages(token);
            }
        }
        .subscribeOn(Schedulers.io())
        .observeOn(AndroidSchedulers.mainThread())
        .subscribe(new Consumer<Messages>() {
            @Override
            public void accept(Messages messages) {
                // 处理显示消息列表
                showMessages(messages);
            }
        });
  • doOnNext()
    输出元素的准备工作,一般用于获取网络数据后保存到数据库的操作,因为数据库操作是耗时任务需要在子线程执行
Observable.fromIterable(arrayList).flatMap(new Function<List<String>, Observable<String>>() {
                @Override
                public Observable<String> apply(List<String> strings) throws Exception {
                    return Observable.fromIterable(strings);
                }
            }).doOnNext(new Consumer<String>() {
                @Override
                public void accept(String s) throws Exception {
                    Log.i(TAG, "输出元素之前的准备工作: "+s);
                }
            })
            .subscribeOn(Schedulers.io())     
            .observeOn(AndroidSchedulers.mainThread())
            .subscribe(new Consumer<String>() {
                @Override
                public void accept(String s) throws Exception {
                    Log.i(TAG, "accept: " + s);
                }
            });
  • doOnSubscribe()
    Observable.doOnSubscribe() 。它和 Subscriber.onStart() 同样是在 subscribe() 调用后而且在事件发送前执行,但区别在于它可以指定线程。默认情况下, doOnSubscribe() 执行在 subscribe() 发生的线程;而如果在 doOnSubscribe() 之后有 subscribeOn() 的话,它将执行在离它最近的 subscribeOn() 所指定的线程。
Observable.fromIterable(arrayList).flatMap(new Function<List<String>, Observable<String>>() {
                @Override
                public Observable<String> apply(List<String> strings) throws Exception {
                    Log.i(TAG, "flatMap操作: ");
                    return Observable.fromIterable(strings);
                }
            })
            .subscribeOn(Schedulers.io())
            .doOnSubscribe(new Consumer<Disposable>() {
                @Override
                public void accept(Disposable disposable) throws Exception {
                    Log.i(TAG, "事件发送之前:比如请求网络之前ProgressBar转圈操作");
                }
            })
            .subscribeOn(AndroidSchedulers.mainThread()) // 指定主线程
            .observeOn(Schedulers.io())
            .doOnNext(new Consumer<String>() {
                @Override
                public void accept(String s) throws Exception {
                    Log.i(TAG, "输出元素之前的准备工作: "+s);
                }
            })
            .observeOn(AndroidSchedulers.mainThread())
            .subscribe(new Consumer<String>() {
                @Override
                public void accept(String s) throws Exception {
                    Log.i(TAG, "accept: " + s);
                }
            });

            //事件打印结果
            com.liujian.rxjava I/MainActivity: 事件发送之前:比如请求网络之前ProgressBar转圈操作
            com.liujian.rxjava I/MainActivity: flatMap操作: 
            com.liujian.rxjava I/MainActivity: 输出元素之前的准备工作: A
            com.liujian.rxjava I/MainActivity: accept: A
            com.liujian.rxjava I/MainActivity: flatMap操作: 
            com.liujian.rxjava I/MainActivity: accept: B
            com.liujian.rxjava I/MainActivity: 输出元素之前的准备工作: C
            com.liujian.rxjava I/MainActivity: accept: C
  1. 线程控制-Scheduler(线程调度器)
    在默认情况下,即在不指定线程的情况下,RxJava遵循的是在哪个线程生产事件,就在哪个线程消费事件
  • Schedulers.immediate():默认的Scheduler。即在哪个线程生产事件,就在哪个线程消费事件
  • Schedulers.newThread():总是启用新线程,并在新线程执行操作。
  • Schedulers.io():I/O 操作(读写文件、读写数据库、网络信息交互等)所使用的Scheduler。行为模式和newThread()差不多,区别在于io()的内部实现是是用一个无数量上限的线程池,可以重用空闲的线程,因此多数情况下 io() 比 newThread() 更有效率。不要把计算工作放在 io() 中,可以避免创建不必要的线程。
  • Schedulers.computation():计算所使用的Scheduler。这个计算指的是 CPU 密集型计算,即不会被I/O等操作限制 性能的操作,例如图形的计算。这个Scheduler使用的固定的线程池,大小为 CPU 核数。不要把 I/O 操作放在 computation()中,否则I/O操作的等待时间会浪费CPU。
  • 另外,RxAndroid 还有一个专用的 AndroidSchedulers.mainThread(),它指定的操作将在 Android 主线程运行。
Observable.just(1,2,3,4)
          .subscribeOn(Schedulers.io()) //改变调用它之前代码的线程
          .observeOn(AndroidSchedulers.mainThread()) //改变调用它之后代码的线程
          .subscribe(new Consumer<Integer>() {
              @Override
              public void accept(Integer integer) throws Exception {
                 //主线程显示数据
              }
          });
  1. 线程控制-Scheduler(二)
    实现线程的多次切换
    注意:不同于 observeOn() , subscribeOn() 的位置放在哪里都可以,但它是只能调用一次的。
Observable.just(R.mipmap.ic_launcher)
              .subscribeOn(Schedulers.io())//指定Observable的操作运行在io()中
              .observeOn(Schedulers.newThread())//指定map运行于newThread()中
              .map(new Function<Integer, Drawable>() {
                    @Override
                    public Drawable apply(Integer integer)throws Exception  {
                        return getResources().getDrawable(integer);
                    }
                })
              .observeOn(AndroidSchedulers.mainThread())//指定Subscriber的代码运行在主线程
              .subscribe(new Consumer<Drawable>() {

                    @Override
                    public void accept(Drawable drawable) throws Exception {
                        iv_iamgeview.setImageDrawable(drawable);
                    }
                });
  1. 使用场景和使用方式
- 与Retrofit结合使用
      getUser(userId)
          //接口返回数据后把数据存到数据库,当onNext发生时,它被调用,不改变数据流。
          .doOnNext(new Consumer<User>() {
              @Override
              public void accept(User user) {
                  saveOrUpdate2Db(user);
              })
          .subscribeOn(Schedulers.io())     
          .observeOn(AndroidSchedulers.mainThread())
          .subscribe(new Subscriber<User>() {
              @Override
              public void onNext(User user) {
                  userView.setUser(user);
              }

              @Override
              public void onCompleted() {
              }

              @Override
              public void onError(Throwable error) {
                  // Error handling
                  ...
              }
          });
  1. Disposable简介
在RxJava中,用它来切断Observer(观察者)与Observable(被观察者)之间的连接,当调用它的dispose()方法时,

它就会将Observer(观察者)与Observable(被观察者)之间的连接切断, 从而导致Observer(观察者)收不到事件。

注意:当切断被观察者与观察者之间的联系,Observable(被观察者)的事件却仍在继续执行。
  1. Flowable/Subscriber
    Observable和Observer的观察者模式是不支持背压的。所以,当我们使用Observable/Observer的时候,我们需要考虑的是,数据量是不是很大(官方给出以1000个事件为分界线,仅供各位参考)
    背压:事件产生的速度远远快于事件消费的速度,最终导致数据积累越来越多,从而导致OOM等异常。
    需要强调两点:
  • 背压策略的一个前提是异步环境,也就是说,被观察者和观察者处在不同的线程环境中。
  • 背压(Backpressure)并不是一个像flatMap一样可以在程序中直接使用的操作符,他只是一种控制事件流速的策略。

/* 背压(在异步过程中,由于被观察者发射数据过快,而观察者处理数据不及时, * 导致内存里堆积了太多数据,从而OOM,可以选择不同的策略处理该问题) * Flowable对应subscriber */

private void createFlowable() { 
        Flowable<String> flowable = Flowable.create(new FlowableOnSubscribe<String>() {                              
             @Override
             public void subscribe(FlowableEmitter<String> e) throws Exception { 
                   if (!e.isCancelled()) {
                      e.onNext("This");
                      e.onNext("is");
                      e.onNext("RxJava");
                      e.onComplete(); } 
              } //抛弃策略 }, BackpressureStrategy.DROP);

         Subscriber<String> subscriber = new Subscriber<String>() {
               Subscription subscription; 
               @Override
               public void onSubscribe(Subscription s) { 
                 subscription = s; //请求一个数据
                 subscription.request(1); 
               } 

               @Override 
               public void onNext(String s) { 
                  Log.i(TAG, "onNext: " + s); //处理完后,再请求一个数据 
                  subscription.request(1); 
               } 
               @Override 
               public void onError(Throwable e) {
                   Log.i(TAG, "onError: " + e.getLocalizedMessage());
               } 
               @Override 
               public void onComplete() { 
                   Log.i(TAG, "onComplete"); //取消订阅 
                   subscription.cancel(); }
               }; 

        flowable.subscribe(subscriber); 
      }