RxJava的概念


RxJava是一个基于事件流,实现异步操作的库。



RxJava的优势


RxJava非常简洁,异步操作关键的一点是程序的简洁性,在调度过程比较复杂的情况下,异步代码经常会显得很乱也很难读懂。Android开发的AsyncTask 和 Handler,其实都是为了让异步代码更加简洁的初衷。RxJava的优势也是简洁性,随着程序逻辑变的越来越复杂,它依然能够保持简洁。



RxJava与传统代码的比较


通过一个例子看一下,RxJava和传统代码的对比。实现一个加载某一个本地文件夹目录下所有图片的功能:

//传统的实现方式
new Thread() {
    @Override
    public void run() {
        super.run();
        for (File folder : folders) {
            File[] files = folder.listFiles();
            for (File file : files) {
                if (file.getName().endsWith(".png")) {
                    final Bitmap bitmap = getBitmapFromFile(file);
                    getActivity().runOnUiThread(new Runnable() {
                        @Override
                        public void run() {
                            imageCollectorView.addImage(bitmap);
                        }
                    });
                }
            }
        }
    }
}.start();
//RxJava的实现方式
Observable.from(folders)
    .flatMap(new Func1<File, Observable<File>>() {
        @Override
        public Observable<File> call(File file) {
            return Observable.from(file.listFiles());
        }
    })
    .filter(new Func1<File, Boolean>() {
        @Override
        public Boolean call(File file) {
            return file.getName().endsWith(".png");
        }
    })
    .map(new Func1<File, Bitmap>() {
        @Override
        public Bitmap call(File file) {
            return getBitmapFromFile(file);
        }
    })
    .subscribeOn(Schedulers.io())
    .observeOn(AndroidSchedulers.mainThread())
    .subscribe(new Action1<Bitmap>() {
        @Override
        public void call(Bitmap bitmap) {
            imageCollectorView.addImage(bitmap);
        }
    });


RxJava的观察者模式


RxJava异步的实现,是通过一种扩展的观察者模式实现的。


RxJava中四个基本概念:


  • Observable(被观察者)
  • Observer(观察者)
  • subscribe(订阅)
  • event(事件)。

Observable 和 Observer 通过subscribe() 来实现订阅关系,从而Observable可以在需要的时候发出事件来通知Observer。


RxJava的事件回调方法包括: onNext()onCompleted()onError()


onCompleted()  —— 表示事件队列完结的回调。RxJava规定,当不会再有新的 onNext() 发出


                                   时,需要触发onCompleted() 方法作为标志。


onError()           —— 表示事件队列异常。事件处理过程中如果发生异常,就被触发onError(),同


                                   时事件队列自动终止,不允许再有事件发出。


注意⚠️    在一个正确运行的事件序列中, onCompleted() 和  onError() 有且只有一个会触发,两者是互斥的,并且是事件序列的最后一个事件。



RxJava的实现步骤


创建观察者 Observer  ———> 创建被观察者 Observable ———> 创建订阅 Subscribe。



1.创建Observer(观察者)


   观察者Observer,用于决定事件触发时对应着怎样的行为。


   Observer接口的实现如下:


//Observer 接口的实现方式
Observer<String> observer = new Observer<String>() {
    @Override
    public void onNext(String s) {
        Log.d(tag, "Item: " + s);
    }

    @Override
    public void onCompleted() {
        Log.d(tag, "Completed!");
    }

    @Override
    public void onError(Throwable e) {
        Log.d(tag, "Error!");
    }
};


   除了Observer 接口之外,还内置了一个实现了 Observer 接口的抽象类:Subscriber。


//实现了 Observer接口的抽象类 —— Subscriber的方式
Subscriber<String> subscriber = new Subscriber<String>() {
    @Override
    public void onNext(String s) {
        Log.d(tag, "Item: " + s);
    }

    @Override
    public void onCompleted() {
        Log.d(tag, "Completed!");
    }

    @Override
    public void onError(Throwable e) {
        Log.d(tag, "Error!");
    }
};


   Subscriber 对 Observer 接口进行了一些扩展,但是它们之间的基本使用方式,是完全一致的。实际上:在RxJava的subscribe过程中,Observer 也总是会先被转换成一个 Subscriber 再使用的。所以如果使用的是基本功能,它们两个用哪个都是可以的。



Observer 和 Subscriber 的区别:


   1.1 onStart()  —— 它是 Subscriber 里面增加的方法。它会在 subscribe 刚开始,而事件还未发


                                 送之前被调用,用于做一些准备的工作,例如数据的清零或者重置。它是一


                                 个可选方法,默认的实现为空。


   1.2 unsubscribe()  —— 它是 Subscriber 实现的另一个接口 Subscription 中的方法,用于取消订


                                 阅。这个方法被调用之后,Subscriber 将不再接收事件。通常在调用这个方


                                 法之前,可以使用 isUnsubscribed()先判断下当前的状态。为了避免内存泄


                                 漏,我们需要在合适的地方调用 unsubscribe() 方法解除引用。



2.创建Observable(被观察者)


   被观察者Observable,决定什么时候触发事件以及触发什么样的事件。RxJava使用 create() 方法来创建一个 Observable,并为它定义事件触发的规则:


Observable observable = Observable.create(new Observable.OnSubscribe<String>() {
    @Override
    public void call(Subscriber<? super String> subscriber) {
        subscriber.onNext("Hello");
        subscriber.onNext("Hi");
        subscriber.onNext("Aloha");
        subscriber.onCompleted();
    }
});

   从上面的代码中可以看到,create() 中传入了一个 OnSubscribe 对象,这个 OnSubscribe 对象会被存储在返回的Observable 对象中,OnSubscribe的作用相当于一个计划表,当 Observable被订阅的时候,OnSubscribe中的call() 方法会自动被调用,事件序列也会依照设定的次序依次触发,先是调用 观察者Subscriber中的onNext()方法三次,再调用观察者 Subscriber中的onCompleted()方法一次。这样,在被观察者中调用了观察者的回调方法就实现了,事件由被观察者向观察者的传递,即观察者模式。


3.创建subscribe(订阅)


   创建了Observer 和Observable之后,再用subscribe() 方法将它们联结起来,整条链子就可以工作起来了。RxJava中的 subscribe(),除了支持 subscribe(Obsever) 和  subscribe(Subscriber),还支持不完整定义的回调,RxJava 会自动根据定义创建出 Subscriber。形式如下:


Action1<String> onNextAction = new Action1<String>() {// onNext()
    @Override
    public void call(String s) {
        Log.d(tag, s);
    }
};
Action1<Throwable> onErrorAction = new Action1<Throwable>() {// onError()
    @Override
    public void call(Throwable throwable) {
        // Error handling
    }
};
Action0 onCompletedAction = new Action0() { // onCompleted()
    @Override
    public void call() {
        Log.d(tag, "completed");
    }
};

// 自动创建 Subscriber ,并使用 onNextAction 来定义 onNext()
observable.subscribe(onNextAction);
// 自动创建 Subscriber ,并使用 onNextAction 和 onErrorAction 来定义 onNext() 和 onError()
observable.subscribe(onNextAction, onErrorAction);
// 自动创建 Subscriber ,并使用 onNextAction、 onErrorAction 和 onCompletedAction 
// 来定义 onNext()、 onError() 和 onCompleted()
observable.subscribe(onNextAction, onErrorAction, onCompletedAction);


RxJava中的ActionX和FuncX


ActionX中的 call() 是没有返回值的,FuncX中的 call() 是有返回值的,它们都有多个不同参数的 call() 方法。



RxJava中的线程控制Scheduler


在不指定线程的情况下,RxJava 默认遵循的是线程不变原则,即:在哪个线程调用了subscribe()就在哪个线程生产事件;在哪个线程生产事件,就在哪个线程消费事件。如果需要切换线程,就需要用到Scheduler调度器了。


1.调度器Scheduler的API


   Scheduler 相当于线程控制器,RxJava通过它来指定每一段代码运行在什么样的线程。RxJava已经内置了几个 Scheduler,它们已经基本满足了大部分的使用场景。


1.1 Scheduler的分类:


Schedulers.immediate() : 这是默认的 Scheduler,直接在当前线程运行,相当于不指定线


                                                      程。


Schedulers.newThread():总是启用新线程,并在新线程中执行操作。


Schedulers.io():                (读写文件、读写数据库、网络请求)等 I/O操作所使用的


                                                      Scheduler。它的行为模式和 newTherad() 差不多,区别在于


                                                      io() 的内部实现了无数量上线的线程池,可以重用空闲的线程,


                                                      因此多数情况下 io() 比 newThread() 更有效率。注意:不要把


                                                      计算相关的工作放在 io() 中,可以避免创建不必要的线程。


Schedulers.computation():计算所使用的 Scheduler。这里说的计算指的是 CPU 密集型                                                              计算,即不会被 I/O 等操作限制性能的操作,例如图形的计                                                              算。它使用了一个固定的线程池,大小为CPU核心数。


                                                          不要在这种调度器中执行I/O,否则等待的时间会浪费CPU。


Schedulers.mainThread(): 它指定的操作将在UI主线程中执行。


1.2 基本的线程切换的API


         subscribeOn() 指定生产事件 发生的线程;


         observeOn() 指定消费事件发生的线程;


Observable.just(1, 2, 3, 4)
    .subscribeOn(Schedulers.io()) // 指定 生产事件 subscribe() 发生在 IO 线程
    .observeOn(AndroidSchedulers.mainThread()) // 指定 消费事件 Subscriber 的回调发生在主线程
    .subscribe(new Action1<Integer>() {
        @Override
        public void call(Integer number) {
            Log.d(tag, "number:" + number);
        }
    });

1.3 复杂的线程切换


          在复杂的逻辑下,会涉及到线程间的多次切换,多次切换遵循的规则是:observeOn() 指定的是它后面的操作所在的线程。因此,如果有多次切换线程的需求,只要在每个想要切换线程操作的位置调用一次observeOn() 即可。不过与observeOn() 不同,subscribeOn() 的位置放在哪里都可以,但是只能调用一次。


Observable.just(1, 2, 3, 4) // IO 线程,由 subscribeOn() 指定
    .subscribeOn(Schedulers.io())
    .observeOn(Schedulers.newThread())
    .map(mapOperator) // 新线程,由 observeOn() 指定
    .observeOn(Schedulers.io())
    .map(mapOperator2) // IO 线程,由 observeOn() 指定
    .observeOn(AndroidSchedulers.mainThread)
    .subscribe(subscriber);  // Android 主线程,由 observeOn() 指定


2.调度器Scheduler的原理


   TODO??????



RxJava中的变换


RxJava提供了对事件序列进行变换的支持,事件序列变换是RxJava的核心功能之一,也是RxJava好用的的最大原因。


1.变化的概念


   所谓变换:就是将事件序列中的对象或者整个序列,进行加工处理,转换成不同的事件或者事件序列。


2.变换操作符


   2.1 map()  — 事件对象的直接变换


         操作符map()将参数中的String对象转换成了一个Bitmap对象后返回,而在经过 map() 方法后,事件的参数类型也由String转为了Bitmap。map()的转换属于直接变换一个事件对象。


Observable.just("images/logo.png") // 输入类型 String
    .map(new Func1<String, Bitmap>() {
        @Override
        public Bitmap call(String filePath) { // 参数类型 String
            return getBitmapFromPath(filePath); // 返回类型 Bitmap
        }
    })
    .subscribe(new Action1<Bitmap>() {
        @Override
        public void call(Bitmap bitmap) { // 参数类型 Bitmap
            showBitmap(bitmap);
        }
    });


  2.2 flatMap() —将原来Observable发射的每个数据,都转换为一个个新的Observable,并发射。flatMap() 和 map()有一个共同点:都是把原来发射的数据转换之后返回一个新的事件对象。


不同点是: flatMap() 中返回的是个 Observable对象,并且这个新的Observable对象并不会直接发送。flatMap() 的原理是这样的:1.使用传入的事件对象创建一个Observable对象;2.并不会直接发送这个新的Observable,而是将它激活,于是iu开始发送事件;3.每一个转换出来的Observable发送的事件,都会被汇入同一个Observable,而这个 Observable 负责将这些事件统一交给 Subscriber 的回调方法。


Student[] students = ...;
Subscriber<Course> subscriber = new Subscriber<Course>() {
    @Override
    public void onNext(Course course) {
        Log.d(tag, course.getName());
    }
    ...
};
Observable.from(students)
    .flatMap(new Func1<Student, Observable<Course>>() {
        @Override
        public Observable<Course> call(Student student) {
            return Observable.from(student.getCourses());
        }
    })
    .subscribe(subscriber);