RxJava学习笔记(一)

该笔记通过“RxJava 详解”学习记录


学习RxJava之前需要了解“观察者模式”


RxJava四个基本概念

1、Observable — 被观察者
2、Observer — 观察者
3、Subscribe — 订阅
4、事件

RxJava有两种事件:

1、普通事件 onNext()
2、特殊事件 onCompleted() — 时间队列完结。当不会再有新的onNext()发出时,需出发onCompleted()方法作为标志。
onError() — 事件队列异常。当事件处理过程中出现异常时,onError会被触发,同时队列自动终止。
注:一个正确的事件队列中,onCompleted()和onError()有且只有一个,并且是事件序列中的最后一个。onCompleted()与onError()二者互斥,即在队列中调用了其中一个,就不应该在调用另一个。

创建Observer,即观察者

它决定事件触发时将有怎样的行为。

Observer<String> observer = new Observer<String>(){
    @Override
    public void onNext(String s){ Log.d(tag,s); }
    @Override
    public void onCompleted(){ Log.d(tag,"Completed!"); }
    @Override
    public void onError(Throwable e){ Log.d(tag,s); }
}

或可以

创建Subscriber,即订阅者

它是Observer的抽象类,对Observer接口进行了拓展。

Subscriber<String> subscriber = new Subscriber<String>(){
    @Override
    public void onNext(String s){ Log.d(tag,s); }
    @Override
    public void onCompleted(){ Log.d(tag,"Completed!"); }
    @Override
    public void onError(Throwable e){ Log.d(tag,s); }
}

Observer与Subscriber之间的区别:

1.onStart():这是Subscriber增加的方法。它会在subscribe(订阅)刚开始,而事件还未发送之前被调用,可以用于做一些准备工作,例如数据的清零或重置。这是一个可选方法,默认情况下它的实现为空。需要注意的是,如果对准备工作的线程有要求(例如弹出一 个显示进度的对话框,这必须在主线程执行),onStart()就不适用了,因为它总是在subscribe(订阅)所发生的线程被调用,而不能指定线程。要在指定的线程来做准备工作,可以使用 doOnSubscribe() 方法。
2.unsubscribe():这是Subscriber所实现的另一个接口Subscription的方法,用于取消订阅。在这个方法被调用后,Subscriber将不再接收事件。一般在这个方法调用前,可以使用isUnsubscribed()先判断一下状态。unsubscribe()这个方法很重要,因为在subscribe()之后,Observable会持有Subscriber的引用,这个引用如果不能及时被释放,将有内存泄露的风险。所以最好保持一个原则:要在不再使用的时候尽快在合适的地方(例如onPause() onStop() 等方法中)调用 unsubscribe() 来解除引用关系,以避免内存泄露的发生。

创建Observable,即被观察者

它决定什么时候触发时间以及吃法怎样的时间。

1.使用create()方法创建

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会被存储在返回的Observale对象中,他的作用相当于一个计划表,当Observable被订阅时,OnSubscribe的call()方法会自动被调用,事件序列就会依照设定依次触发。

2.使用just(T…)方法创建。将传入的参数依次发送出来。

Observable observable = Observable.just("Hello", "Hi", "Aloha");

3.使用from(T[])/from(Iterable

String[] words = {"Hello", "Hi", "Aloha"};
Observable observable = Observable.from(words);

Subscribe(订阅)

observable.subscribe(observer);
// 或者:
observable.subscribe(subscriber);

为什么不能颠倒顺序,即为什么不能observer.subscribe(obserable):
Observable.subscribe(Subscriber)内部核心代码

public Subscription subscribe(Subscriber subscriber) {
    subscriber.onStart();
    onSubscribe.call(subscriber);
    return subscriber;
}

可以看到,subscribe()做了3件事:
1.调用Subscriber.onStart()方法。
2.调用Observable中的Onsubscribe.call(Subscriber)。在这里,事件发送的逻辑开始运行。从这也可以看出,在 RxJava 中,Observable 并不是在创建的时候就立即开始发送事件,而是在它被订阅的时候,即当 subscribe() 方法执行的时候。
3.将传入的Subscriber作为Subscription返回,方便unsubscribe()。

subscribe()不完整定义的回调

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);

举例:

// 将字符串数组 names 中的所有字符串依次打印出来:
String[] names = ...;
Observable.from(names)
    .subscribe(new Action1<String>() {
        @Override
        public void call(String name) {
            Log.d(tag, name);
        }
    });

//由指定的一个 drawable 文件 id drawableRes 取得图片,并显示在 ImageView 中,并在出现异常的时候打印 Toast 报错
int drawableRes = ...;
ImageView imageView = ...;
Observable.create(new OnSubscribe<Drawable>() {
    @Override
    public void call(Subscriber<? super Drawable> subscriber) {
        Drawable drawable = getTheme().getDrawable(drawableRes));
        subscriber.onNext(drawable);
        subscriber.onCompleted();
    }
}).subscribe(new Observer<Drawable>() {
    @Override
    public void onNext(Drawable drawable) {
        imageView.setImageDrawable(drawable);
    }
    @Override
    public void onCompleted() {
    }
    @Override
    public void onError(Throwable e) {
        Toast.makeText(activity, "Error!", Toast.LENGTH_SHORT).show();
    }
})

线程控制 — Scheduler (调度器)

  1. Schedulers.immediate():在当前线程运行。默认方法。
  2. Schedulers.newThread():启用新线程,并在新线程执行操作。
  3. Schedulers.io():I/O(读写文件、读写数据库、网络交互)操作所用。和newThread()差不多,区别在于io()的内部实现使用一个无数量上限的线程池,可以重用空闲的线程,因此多数情况下io()比newThread()更有效率。不要把计算工作放在io()中,可以避免创建不必要的线程。
  4. Schedulers.computation():计算所使用的Scheduler。该计算指CPU密集型计算,即不会被I/O等操作限制性能操作,例如图形计算。该方法使用固定线程池,大小为CPU核数。不要把I/O操作放到该方法中,否则I/O操作的等待时间会浪费CPU。
  5. AndroidSchedulers.mainThread():Android专有方法,指定操作在Android主线程运行。

以上方法可以使用subscribeOn()和observeOn()两个方法来控制。

  1. subscribeOn():指定subscribe所发生的线程,即Observable.OnSubscibe被激活时所处的线程。可叫作事件产生的线程。
  2. observeOn():指定Subscriber所运行的线程。可叫作事件消费的线程。
    举例:
int drawableRes = ...;
ImageView imageView = ...;
Observable.create(new OnSubscribe<Drawable>() {
    @Override
    public void call(Subscriber<? super Drawable> subscriber) {
        Drawable drawable = getTheme().getDrawable(drawableRes));
        subscriber.onNext(drawable);
        subscriber.onCompleted();
    }
})
.subscribeOn(Schedulers.io()) // 指定 subscribe() 发生在 IO 线程
.observeOn(AndroidSchedulers.mainThread()) // 指定 Subscriber 的回调发生在主线程
.subscribe(new Observer<Drawable>() {
    @Override
    public void onNext(Drawable drawable) {
        imageView.setImageDrawable(drawable);
    }
    @Override
    public void onCompleted() {
    }
    @Override
    public void onError(Throwable e) {
        Toast.makeText(activity, "Error!", Toast.LENGTH_SHORT).show();
    }
});

注:
1.通过observeOn()可以实现多次切换线程。若想要多次切换线程,只需要在要切换线程的位置调用一次observeOn()即可。例如:

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.subscribeOn()的位置可以随便放,但它只能调用一次。

延伸:doOnSubscribe()

Subscriber 的 onStart() 可以用作流程开始前的初始化。然而 onStart() 由于在 subscribe() 发生时就被调用了,因此不能指定线程,而是只能执行在 subscribe() 被调用时的线程。这就导致如果 onStart() 中含有对线程有要求的代码(例如在界面上显示一个 ProgressBar,这必须在主线程执行),将会有线程非法的风险,因为有时你无法预测 subscribe() 将会在什么线程执行。
而与 Subscriber.onStart() 相对应的,有一个方法 Observable.doOnSubscribe() 。它和 Subscriber.onStart() 同样是在 subscribe() 调用后而且在事件发送前执行,但区别在于它可以指定线程。默认情况下, doOnSubscribe() 执行在 subscribe() 发生的线程;而如果在 doOnSubscribe() 之后有 subscribeOn() 的话,它将执行在离它最近的 subscribeOn() 所指定的线程。

Observable.create(onSubscribe)
    .subscribeOn(Schedulers.io())
    .doOnSubscribe(new Action0() {
        @Override
        public void call() {
            progressBar.setVisibility(View.VISIBLE); // 需要在主线程执行
        }
    })
    .subscribeOn(AndroidSchedulers.mainThread()) // 指定主线程
    .observeOn(AndroidSchedulers.mainThread())
    .subscribe(subscriber);

变换

1.事件对象变换 map(),例如:

Observable.just("images/logo.png") // 输入类型 String
    .map(new Func1<String, Bitmap>() {    //将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.事件队列变换 flatMap(),例如:

/**
 * 需求:有一个数据结构【学生】,需要打印每个学生所需要学习的所有课程的名称
*/
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);

3.针对Observable自身变换 compose(Transformer),例如:

/**
 * 需求:假设程序中有多个 Observable,并且都需要应用一组相同的 lift() 变换
*/
public class LiftAllTransformer implements Observable.Transformer<Integer, String> {
    @Override
    public Observable<String> call(Observable<Integer> observable) {
        return observable
            .lift1()
            .lift2()
            .lift3()
            .lift4();
    }
}
...
Transformer liftAll = new LiftAllTransformer();
observable1.compose(liftAll).subscribe(subscriber1);
observable2.compose(liftAll).subscribe(subscriber2);
observable3.compose(liftAll).subscribe(subscriber3);
observable4.compose(liftAll).subscribe(subscriber4);

另附几篇博客参考:
RxJava源码初探:http://www.apkbus.com/blog-705730-60688.html
RxJava全面总结:http://www.apkbus.com/blog-705730-60454.html
玩透RxJava基础知识:http://www.apkbus.com/blog-705730-60437.html

猜你喜欢

转载自blog.csdn.net/Android_Programmer/article/details/78065519