RxJava简易上手指南
标签(空格分隔): android rxjava
作者:陈小默
版权声明:禁止商用,转载请注明出处
本文章仅作为初学者最快上手实践,不会深入涉及代码原理,有兴趣的朋友可以参阅 扔物线-给Android开发者的RxJava详解
一、介绍
RxJava通过扩展的观察者模式实现异步操作
Observable:被观察者
Observer:观察者
Subscriber:消息订阅者
其中的关系是观察者(Observer)或者消息订阅者(Subscriber)通过订阅(subscribe)的方式观察被观察者(Observable)的行为
二、回调方法介绍
2.1 观察者对象
//观察者对象 实现了观察者接口,其中泛型代表了观察者需要的相应对象
Observer<String> observer = new Observer<String>() {
@Override
public void onCompleted() {
//观察任务完成时回调
}
@Override
public void onError(Throwable e) {
//发生错误时回调,并即刻终止事件序列的传递(与onCompleted方法互斥)
}
@Override
public void onNext(String s) {
//监听事件序列回调
}
};
2.2 消息订阅者对象
消息订阅者是实现了观察者接口的抽象类。如果使用观察者对象,在运行时仍会被包装为消息订阅这对象运行
//消息订阅者对象
Subscriber<Bitmap> subscriber = new Subscriber<Bitmap>() {
@Override
public void onStart() {
//当消息订阅动作完成时,自动回调此方法
//此方法运行在订阅行为发生的线程
//不安全,建议初始化方法使用Observable.doOnSubscribe()
}
@Override
public void onCompleted() {
}
@Override
public void onError(Throwable e) {
}
@Override
public void onNext(Bitmap bitmap) {
}
};
2.3 观察对象
该对象代表被观察者的行为,并将行为告知订阅者
//观察行为对象
Observable.OnSubscribe<String> onSubscribe = new Observable.OnSubscribe<String>() {
/**
* 在此方法将行为通知给观察者对象
* @param subscriber 框架传入的观察者对象
*/
@Override
public void call(Subscriber<? super String> subscriber) {
subscriber.onNext("Hello ");
subscriber.onNext("World ");
subscriber.onCompleted();//此方法必须被调用,代表事件结束
}
};
2.4 不完整定义回调
以下三个对象分别代表观察者对象的三种行为,使用时可以根据需求完成部分回调
//话说这些接口的名字太不友好了
Action1<String> onNext = new Action1<String>() {
@Override
public void call(String s) {
//监听事件序列回调
}
};
Action1<Throwable> onError = new Action1<Throwable>() {
@Override
public void call(Throwable s) {
//发生错误时回调,并即刻终止事件序列的传递
}
};
Action0 onComplete = new Action0() {
@Override
public void call() {
//观察任务完成时回调
}
};
三、基本实现
//加载观察对象
Observable<String> observable = Observable.create(onSubscribe);
//加载消息订阅者(观察者)对象,此时立即调用onStart()方法
observable.subscribe(observer);
//不使用消息订阅者对象,采用不完整定义(任选其一)
observable.subscribe(onNext);
observable.subscribe(onNext,onError);
observable.subscribe(onNext,onError,onComplete);
3.1 观察者对象的加载
加载观察对象的方式还有另外两种形式
3.1.1 from
//传入数组
String[] sList= {"Hello ","World "};
observable = Observable.from(sList);
3.1.2 just
//看到这个方法的若干重载的实现,都开始怀疑人生了,难道RxJava诞生的时候变长参数还没有支持?
observable = Observable.just("Hello ","World ");
四、线程调度介绍
在不使用线程调度的情况下,观察者和被观察者处于同一线程当中,如果想要切换线程则必须使用线程调度方法指挥观察者的运行环境,先来介绍几个参数:
- Schedulers.immediate();没有线程切换过程,事件在哪里产生就在哪里消费
- Schedulers.newThread();将当前事件切换到新建线程中执行
- Schedulers.io();同样也是开启新线程,但是这里会有线程的复用,建议将耗时操作(文件读写,网络请求,数据库读写)在这里执行。
- Schedulers.computation();固定线程池,用来处理计算密集型操作(图形渲染等),不建议将耗时操作放在此线程中执行,影响效率。你要问为什么,回去看看你操作系统的课本或者参阅博客 浅谈Java两种并发类型——计算密集型与IO密集型
到底如何进行线程调度呢?
这里介绍两个方法:subscribeOn() 和 observeOn(),这些方法可以多次调用,用来指定其后传入对象的执行状态
代码
// 以下调用了两次在不同线程状态切换
observable.subscribeOn(Schedulers.newThread())//订阅行为运行在子线程
.observeOn(AndroidSchedulers.mainThread())//观察者运行在UI线程
.subscribe(subscriber);
observable.subscribeOn(Schedulers.computation())//订阅行为运行在子线程
.observeOn(Schedulers.io())//观察者运行在IO线程
.subscribe(observer);
五、变换的基本介绍
常用的变换有两种 map()和flatMap(),其中的参数都是Func1接口的实现类。
变换的call方法执行在消息订阅者线程
5.1 Func1接口的两种实现方式
该接口用于泛型所指定的参数的变换
5.1.1 Map变幻对象
Func1<String , Bitmap> loadImage = new Func1<String, Bitmap>() {
@Override
public Bitmap call(String url) {
//在这里完成网络请求加载图片并返回
return null;
}
};
observable.map(loadImage)
.subscribe(observer);
5.1.2 FlatMap变幻对象
上面的Map变换对象还算是比较好理解,但是下面的faltMap方法就不那么好理解了,下面用一个获取学生上课的班级信息的例子来演示:
定义班级信息
public class ClassInfo {
private String className;//班级名
...getter & setter
}
定义学生信息
public class Student {
private List<ClassInfo> classes;
...getter & setter
}
下面模拟获取学生班级名称
Observable.just(new Student(), new Student())
.flatMap(new Func1<Student, Observable<String>>() {
//第一次变换,从student对象中取出教室信息列表
@Override
public Observable<String> call(Student student) {
return Observable.from(student.getClasses())
.map(new Func1<ClassInfo, String>() {
//第二次变换,从ClassInfo对象取出班级名称
@Override
public String call(ClassInfo classInfo) {
//将得到的班级名发送给观察者
return classInfo.getClassName();
}
});
}
}).subscribe(subscriber);
这里用到了两次变换,以此类推,flatMap方法能实现多级数据变换
六、模拟使用场景Demo
以下演示一个网络请求百度lOGO的例子
在MainActivity的onCreate方法
ImageView baidu = (ImageView) findViewById(R.id.baidu);
Observable.just("https://www.baidu.com/img/bd_logo1.png")
.map(new Func1<String, Bitmap>() {
@Override
public Bitmap call(String url) {
//我这里采用okHttp的同步方法下载图片
return download(url);
}
}).subscribeOn(Schedulers.io())//定义IO线程为事件产生线程
.observeOn(AndroidSchedulers.mainThread())//定义主线程为事件消费线程
.doOnSubscribe(new Action0() {
//指定运行线程的方法,在订阅发生时启动,用来替换onStart方法
//这里用来在启动时给ImageView设置默认图片
@Override
public void call() {
baidu.setImageResource(R.mipmap.ic_launcher);
}
}).subscribeOn(AndroidSchedulers.mainThread())//指定doOnSubscribe方法运行在什么线程
//必须放在定义事件产生线程的后面
.subscribe(new Subscriber<Bitmap>() {
@Override
public void onCompleted() {
}
@Override
public void onError(Throwable e) {
baidu.setImageResource(R.mipmap.ic_launcher);
//下载失败显示图标
}
@Override
public void onNext(Bitmap bitmap) {
baidu.setImageBitmap(bitmap);
}
});