RxJava个人学习笔记
主要内容包含以下部分:
- RxJava是什么
- HelloWorld
- 变换
- 操作符
- 切换线程
RxJava是什么
最初学习使用RxJava的时候,很难理解RxJava到底是什么东西,其实耐心多看几遍就会理解了。RxJava其实就是一个处理异步事件的库。作为一个Android开发者肯定遇到过子线程请求数据,主线程更新UI的这样的需求,,使用RxJava就可以简单明了的完成这样的功能。
HelloWorld
首先在module的gradle文件里添加依赖(Android Studio3.0,Gradle3.0之后compile变为implementation)
implementation 'io.reactivex.rxjava2:rxjava:2.1.3'
implementation 'io.reactivex.rxjava2:rxandroid:2.0.1'
RxJava最核心的两个东西是Observable(被观察者)和Observer(观察者)。被观察者发出一系列的事件之后,观察者根据这些事件做出处理。
首先创建一个Observable对象
Observable<String> observable=Observable.create(new ObservableOnSubscribe<String>() {
@Override
public void subscribe(ObservableEmitter<String> e) throws Exception {
e.onNext("Hello World");
}
这里被观察者发出了一条消息,这条消息会传到观察者那里处理。
Observer<String> observer=new Observer<String>() {
@Override
public void onSubscribe(Disposable d) {
}
@Override
public void onNext(String s) {
Log.v("rxjava",s);
}
@Override
public void onError(Throwable e) {
}
@Override
public void onComplete() {
}
};
然后将observer订阅observable
observable.subscribe(observer);
运行之后Log显示如下:
10-16 11:06:33.817 3095-3095/com.wangguan.demos V/rxjava: Hello World
上边的写法也可以串起来写成链式的操作:
Observable.create(new ObservableOnSubscribe<String>() {
@Override
public void subscribe(ObservableEmitter<String> emitter) throws Exception {
emitter.onNext("Hello");
emitter.onNext("World");
}
}).subscribe(new Observer<String>() {
@Override
public void onSubscribe(Disposable d) {
}
@Override
public void onNext(String s) {
Log.v("rxjava",s);
}
@Override
public void onError(Throwable e) {
}
@Override
public void onComplete() {
}
});
是不是觉得为了写一行代码要实现这么多的接口很麻烦,subscribe也可以调用简单的Observer:Consumer。Consumer只需要实现Observer的onNext即可。
Observable.create(new ObservableOnSubscribe<String>() {
@Override
public void subscribe(ObservableEmitter<String> emitter) throws Exception {
emitter.onNext("Hello");
emitter.onNext("World");
}
}).subscribe(new Consumer<String>() {
@Override
public void accept(String s) throws Exception {
Log.v("rxjava",s);
}
});
Observable还可以传入数组形式的参数,比如
String[] words = {"Hello", "World"};
Observable observable = Observable.fromArray(words);
这样的写法等价于上边的
Observable<String> observable=Observable.create(new ObservableOnSubscribe<String>() {
@Override
public void subscribe(ObservableEmitter<String> e) throws Exception {
e.onNext("Hello");
e.onNext("World");
e.onNext("RXJAVA");
}
变换
有时候代码里面传入的参数和需要使用的数据类型不同,比如需要传入int类型的drawable的id得到Bitmap的图片。这时候怎么写呢?当然可以在onNext方法中通过int得到Bitmap然后显示在ImageView中。如下:
Observable.create(new ObservableOnSubscribe<Integer>() {
@Override
public void subscribe(ObservableEmitter<Integer> emitter) throws Exception {
emitter.onNext(R.mipmap.ic_launcher);
}
}).subscribe(new Observer<Integer>() {
@Override
public void onSubscribe(Disposable d) {
}
@Override
public void onNext(Integer id) {
Bitmap bmp = BitmapFactory.decodeResource(getResources(), id);
imageView.setImageBitmap(bmp);
}
@Override
public void onError(Throwable e) {
}
@Override
public void onComplete() {
}
});
但是RxJava最强大的地方是可以把逻辑写的简明。如果在onNext得到的就是Bitmap 是不是更好呢?当然也是可以的。使用map变换符就可以了。
Observable.create(new ObservableOnSubscribe<Integer>() {
@Override
public void subscribe(ObservableEmitter<Integer> emitter) throws Exception {
emitter.onNext(R.mipmap.ic_launcher);
}
}).map(new Function<Integer, Bitmap>() {
@Override
public Bitmap apply(Integer id) throws Exception {
Bitmap bmp = BitmapFactory.decodeResource(getResources(), id);
return bmp;
}
}).subscribe(new Observer<Bitmap>() {
@Override
public void onSubscribe(Disposable d) {
}
@Override
public void onNext(Bitmap bmp) {
imageView.setImageBitmap(bmp);
}
@Override
public void onError(Throwable e) {
}
@Override
public void onComplete() {
}
});
首先R.mipmap.ic_launcher会在map里做处理,通过Function将Integer转成Bitmap,然后在onNext里得到的就是Bitmap类型的数据了。
操作符
操作符是为了解决对Observable对象的变换的问题,操作符用于在Observable和最终的Subscriber之间修改Observable发出的事件。
常见的操作符有:
- fromArray
- map
- flatMap
- filter
- take
- doOnNext
切换线程
在实际Android开发中,网络请求是最常见的处理之一。一般都是在子线程中请求数据,然后在主线程中修改UI,原因都懂的。那么刚才修改图片的例子是不是一直在主线程中运行呢?刚才的代码修改一下,打印一下线程名称。如下:
Observable.create(new ObservableOnSubscribe<Integer>() {
@Override
public void subscribe(ObservableEmitter<Integer> emitter) throws Exception {
Log.v("rxjava",Thread.currentThread().getName());
emitter.onNext(R.mipmap.ic_launcher);
}
}).map(new Function<Integer, Bitmap>() {
@Override
public Bitmap apply(Integer id) throws Exception {
Log.v("rxjava",Thread.currentThread().getName());
Bitmap bmp = BitmapFactory.decodeResource(getResources(), id);
return bmp;
}
}).subscribe(new Consumer<Bitmap>() {
@Override
public void accept(Bitmap bitmap) throws Exception {
Log.v("rxjava",Thread.currentThread().getName());
imageView.setImageBitmap(bitmap);
}
});
日志为:
10-19 05:53:56.124 4187-4187/com.wangguan.demos V/rxjava: main
10-19 05:53:56.124 4187-4187/com.wangguan.demos V/rxjava: main
10-19 05:53:56.130 4187-4187/com.wangguan.demos V/rxjava: main
根据log的输出显然全部的处理都是在主线程中运行的。Android4.0以后,如果直接在主线程中发起网络请求程序直接会发生异常,那么应该怎么样呢?
Observable.create(new ObservableOnSubscribe<String>() {
@Override
public void subscribe(ObservableEmitter<String> emitter) throws Exception {
Log.v("rxjava1", Thread.currentThread().getName());
emitter.onNext("https://ss0.bdstatic.com/5aV1bjqh_Q23odCf/static/superman/img/logo/bd_logo1_31bdc765.png");
}
}).subscribeOn(Schedulers.io())
.map(new Function<String, Bitmap>() {
@Override
public Bitmap apply(String imageUrl) throws Exception {
Log.v("rxjava2", Thread.currentThread().getName());
URL url = new URL(imageUrl);
Bitmap bmp = BitmapFactory.decodeStream(url.openStream());
return bmp;
}
}).observeOn(AndroidSchedulers.mainThread())
.subscribe(new Consumer<Bitmap>() {
@Override
public void accept(Bitmap bitmap) throws Exception {
Log.v("rxjava3", Thread.currentThread().getName());
imageView.setImageBitmap(bitmap);
}
});
这里多了两行代码:
subscribeOn(Schedulers.io())
observeOn(AndroidSchedulers.mainThread())
日志如下:
10-19 06:51:05.850 5813-6007/com.wangguan.demos V/rxjava1: RxCachedThreadScheduler-2
10-19 06:51:05.851 5813-6007/com.wangguan.demos V/rxjava2: RxCachedThreadScheduler-2
10-19 06:51:05.980 5813-5813/com.wangguan.demos V/rxjava3: main
看了log之后,这两行代码的作用就很明了了:起到了切换线程的作用。
subscribeOn把被观察者的线程切换到了IO线程。
observeOn把观察者的线程切换到了主线程。
所以把String转成Bitmap的处理也在IO线程中运行。
在RxJava中, 已经内置了很多线程选项,比如
- Schedulers.io() 代表io操作的线程, 通常用于网络,读写文件等io密集型的操作
- Schedulers.computation() 代表CPU计算密集型的操作, 例如需要大量计算的操作
- Schedulers.newThread() 代表一个常规的新线程
- AndroidSchedulers.mainThread() 代表Android的主线程