您的位置:首页 > 编程语言 > Java开发

RxJava 简易上手指南

2016-07-20 11:42 477 查看

RxJava简易上手指南

标签(空格分隔): android rxjava

作者:陈小默

版权声明:禁止商用,转载请注明出处

[toc]

本文章仅作为初学者最快上手实践,不会深入涉及代码原理,有兴趣的朋友可以参阅 扔物线-给Android开发者的RxJava详解
#一、介绍
RxJava通过扩展的观察者模式实现异步操作

Observable:被观察者
Observer:观察者
Subscriber:消息订阅者

其中的关系是观察者(Observer)或者消息订阅者(Subscriber)通过订阅(subscribe)的方式观察被观察者(Observable)的行为

#二、回调方法介绍
##2.1 观察者对象<span id = "观察者对象"></span>

//观察者对象 实现了观察者接口,其中泛型代表了观察者需要的相应对象
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 消息订阅者对象<span id = "消息订阅者对象"></span>

消息订阅者是实现了观察者接口的抽象类。如果使用观察者对象,在运行时仍会被包装为消息订阅这对象运行

//消息订阅者对象
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 观察对象<span id = "观察对象"></span>

该对象代表被观察者的行为,并将行为告知订阅者

//观察行为对象
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(),这些方法可以多次调用,用来指定其后传入对象的执行状态

subscribeOn():订阅者线程(事件产生线程)该方法用来指定订阅操作执行过程所在的线程,既观察对象中call方法运行所在的线程。

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);
}
});
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: