Rxjava的理解

Rxjava复习专用


Rxjava —— 四个基本概念

  • RxJava 有四个基本概念:Observable (可观察者,即被观察者)、 Observer (观察者)、 subscribe (订阅)、事件。
  • Observable 和 Observer 通过 subscribe() 方法实现订阅关系,从而 Observable 可以在需要的时候发出事件来通知 Observer。
Rxjava的理解_第1张图片

Observer —— 观察者

它决定事件触发的时候将有怎样的行为
  • Observer 接口
  • Subscriber 抽象类,实现了Observer和Subscription
    不仅基本使用方式一样,实质上,在 RxJava 的 subscribe 过程中,Observer 也总是会先被转换成一个 Subscriber 再使用。所以如果你只想使用基本功能,选择 Observer 和 Subscriber 是完全一样的。它们的区别对于使用者来说主要有两点:

两者的区别:
1.Subscriber 多了 onStart( ) 方法,但是该方法发生在 subscribe 发生的线程,不能指定线程
2.Subscriber 多了 unsubscribe( ) 方法, Subscriber 所实现的另一个接口 Subscription 的方法,用于取消订阅

示例代码:
Subscriber subscriber = new Subscriber() {
    @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!");
    }
};

Observable —— 被观察者

它决定什么时候触发事件以及触发怎样的事件
示例代码:
  • create( ) RxJava 最基本的创造事件序列的方法
Observable observable = Observable.create(new Observable.OnSubscribe() {
            @Override
            public void call(Subscriber subscriber) {
                //观察者将会依次调用三次onNext和一次Completed
                subscriber.onNext("Hello");
                subscriber.onNext("Hi");
                subscriber.onNext("Aloha");
                subscriber.onCompleted();
            }
        });
  • just( T... ) 将传入的参数依次发送出来。
Observable observable = Observable.just("Hello", "Hi", "Aloha");
// 将会依次调用:
// onNext("Hello");
// onNext("Hi");
// onNext("Aloha");
// onCompleted();
  • from(T[ ])
String[] words = {"Hello", "Hi", "Aloha"};
Observable observable = Observable.from(words);
// 将会依次调用:
// onNext("Hello");
// onNext("Hi");
// onNext("Aloha");
// onCompleted();

Subscribe —— 订阅

创建了 Observable 和 Observer 之后,再用 subscribe() 方法将它们联结起来,整条链子就可以工作了
observable.subscribe(observer);
// 或者:
observable.subscribe(subscriber);
Observable.subscribe(Subscriber) 的内部实现是这样的(仅核心代码):
// 注意:这不是 subscribe() 的源码,而是将源码中与性能、兼容性、扩展性有关的代码剔除后的核心代码。
// 如果需要看源码,可以去 RxJava 的 GitHub 仓库下载。
public Subscription subscribe(Subscriber subscriber) {
    subscriber.onStart();
    onSubscribe.call(subscriber);
    return subscriber;
}

调用 Subscriber.onStart() 。这个方法在前面已经介绍过,是一个可选的准备方法。
调用 Observable 中的 OnSubscribe.call(Subscriber) 。在这里,事件发送的逻辑开始运行。从这也可以看出,在 RxJava 中, Observable 并不是在创建的时候就立即开始发送事件,而是在它被订阅的时候,即当 subscribe() 方法执行的时候。
将传入的 Subscriber 作为 Subscription 返回。这是为了方便 unsubscribe().

除了 subscribe(Observer) 和 subscribe(Subscriber) ,subscribe() 还支持不完整定义的回调,RxJava 会自动根据定义创建出 Subscriber 。形式如下:
Action1 onNextAction = new Action1() {
    // onNext()
    @Override
    public void call(String s) {
        Log.d(tag, s);
    }
};
Action1 onErrorAction = new Action1() {
    // 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() {
        @Override
        public void call(String name) {
            Log.d(tag, name);
        }
    });
  • 由 id 取得图片并显示
由指定的一个 drawable 文件 id drawableRes 取得图片,并显示在 ImageView 中,并在出现异常的时候打印 Toast 报错:
int drawableRes = ...;
ImageView imageView = ...;
Observable.create(new OnSubscribe() {
    @Override
    public void call(Subscriber subscriber) {
        Drawable drawable = getTheme().getDrawable(drawableRes));
        subscriber.onNext(drawable);
        subscriber.onCompleted();
    }
}).subscribe(new Observer() {
    @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();
    }
});

以上为RxJava的基本使用,不涉及线程切换.以下开始切换


线程控制 —— Scheduler

相当于线程控制器,RxJava 通过它来指定每一段代码应该运行在什么样的线程
  • Scheduler的API
  1. Schedulers.immediate(): 直接在当前线程运行,相当于不指定线程。这是默认的 Scheduler。
  2. Schedulers.newThread(): 总是启用新线程,并在新线程执行操作。
  3. Schedulers.io(): I/O 操作(读写文件、读写数据库、网络信息交互等)所使用的 Scheduler。行为模式和 newThread() 差不多,区别在于 io() 的内部实现是是用一个无数量上限的线程池,可以重用空闲的线程,因此多数情况下 io() 比 newThread() 更有效率。不要把计算工作放在 io() 中,可以避免创建不必要的线程。
  4. Schedulers.computation(): 计算所使用的 Scheduler。这个计算指的是 CPU 密集型计算,即不会被 I/O 等操作限制性能的操作,例如图形的计算。这个 Scheduler 使用的固定的线程池,大小为 CPU 核数。不要把 I/O 操作放在 computation() 中,否则 I/O 操作的等待时间会浪费 CPU。
  5. 另外, Android 还有一个专用的 AndroidSchedulers.mainThread(),它指定的操作将在 Android 主线程运行。

有了这几个 Scheduler,就可以使用

  • subscribeOn( )
  • observeOn( )
    两个方法来对线程进行控制了。subscribeOn( ) : 指定 subscribe() 所发生的线程,即 Observable.OnSubscribe 被激活时所处的线程。或者叫做事件产生的线程。observeOn( ) : 指定 Subscriber 所运行在的线程。或者叫做事件消费的线程。

示例代码:非常常见,它适用于多数的 『后台线程取数据,主线程显示』的程序策略。

//将图片路径转为bitmap
Observable.just(1, 2, 3, 4)
    .subscribeOn(Schedulers.io()) // 指定 subscribe() 发生在 IO 线程
    .observeOn(AndroidSchedulers.mainThread()) // 指定 Subscriber 的回调发生在主线程
    .subscribe(new Action1() {
        @Override
        public void call(Integer number) {
            Log.d(tag, "number:" + number);
        }
    });

变换 —— 将事件序列中的对象或整个序列进行加工处理,转换成不同的事件或事件序列

API
  • map( ) 事件对象的一对一的变换
//将图片路径转为bitmap
Observable.just("images/logo.png") // 输入类型 String
    .map(new Func1() {
        @Override
            public Bitmap call(String filePath) { // 参数类型 String
                return getBitmapFromPath(filePath); // 返回类型 Bitmap
            }
        })
    .subscribe(new Action1() {
        @Override
        public void call(Bitmap bitmap) { // 参数类型 Bitmap
             showBitmap(bitmap);
        }
     });
  • flatMap( ) 一堆对象变成另一堆对象
//假设有一个数据结构『学生』,现在需要打印出每个学生所需要修的所有课程的名称
Student[] students = ...;
Subscriber subscriber = new Subscriber() {
   @Override
    public void onNext(Course course) {
        Log.d(tag, course.getName());
    }
    ...
};
Observable.from(students)
    .flatMap(new Func1>() {
        @Override
        public Observable call(Student student) {
            return Observable.from(student.getCourses());//这句代码
        }
    })
    .subscribe(subscriber);

解析:

将一堆对象拆分,变成一个个对象,再以一个对象为单位创建观察者,Observable.from(student.getCourses())这句代码看出,新建的观察者发送事件.全部汇入Subscriber的回调中

  • flatMap() 和 map() 有一个相同点:它也是把传入的参数转化之后返回另一个对象。
  • 但需要注意,和 map() 不同的是, flatMap() 中返回的是个 Observable(观察者) 对象,并且这个 Observable 对象并不是被直接发送到了 Subscriber 的回调方法中。
  • flatMap() 的原理是这样的:
    1. 使用传入的事件对象创建一个 Observable 对象;
    2. 并不发送这个 Observable, 而是将它激活,于是它开始发送事件;
    3. 每一个创建出来的 Observable 发送的事件,都被汇入同一个 Observable ,而这个 Observable 负责将这些事件统一交给 Subscriber 的回调方法。这三个步骤,把事件拆成了两级,通过一组新创建的 Observable 将初始的对象『铺平』之后通过统一路径分发了下去。而这个『铺平』就是 flatMap() 所谓的 flat。
这里略过了变换的原理
  • compose( ) 一堆被观察者都需要变化相同的逻辑,使用此方法
 //假设在程序中有多个 Observable ,并且他们都需要应用一组相同的 lift() 变换。
public class LiftAllTransformer implements Observable.Transformer {
    @Override
    public Observable call(Observable 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);

线程控制 —— 线程的自由控制

代码示例
Observable.just(1, 2, 3, 4) // IO 线程,由 subscribeOn() 指定
    .subscribeOn(Schedulers.io())//===指定了事件发生的线程. subscribeOn() 的位置放在哪里都可以,但它是只能调用一次的。
    .observeOn(Schedulers.newThread())//================指定了接下来map发送的线程
    .map(mapOperator) // 新线程,由 observeOn() 指定
    .observeOn(Schedulers.io())//=======================指定了接下来map发送的线程
    .map(mapOperator2) // IO 线程,由 observeOn() 指定
    .observeOn(AndroidSchedulers.mainThread) //==========制定了接下来消费事件的线程
    .subscribe(subscriber);  // Android 主线程,由 observeOn() 指定

解析:
observeOn() 指定的是 Subscriber(观察者) 的线程,而这个 Subscriber(观察者) 并不是(严格说应该为『不一定是』,但这里不妨理解为『不是』)subscribe() 参数中的 Subscriber(观察者),而是 observeOn() 执行时的当前 Observable 所对应的 Subscriber(观察者),即它的直接下级 Subscriber(观察者) 。换句话说,observeOn() 指定的是它之后的操作所在的线程。因此如果有多次切换线程的需求,只要在每个想要切换线程的位置调用一次 observeOn() 即可
意思就是:RxJava中对Observable进行变化操作都会有对应的Subscriber(观察者) ,我们在操作前设置线程observeOn()就可以指定接下来的Subscriber(观察者)


延伸:doOnSubscribe()

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

解析:
它和 Subscriber.onStart() 同样是在 subscribe() 调用后而且在事件发送前执行,但区别在于它可以指定线程。默认情况下, doOnSubscribe() 执行在 subscribe() 发生的线程;而如果在 doOnSubscribe() 之后有 subscribeOn() 的话,它将执行在离它最近的 subscribeOn() 所指定的线程。


差不多了,该去实际场景中使用了

复习链接
给 Android 开发者的 RxJava 详解 -- [作者:扔物线]

你可能感兴趣的:(Rxjava的理解)