在RxJava中,如果把整个事件流看作是工厂的流水线,Observable就是原料,Observer就是我们的产品经理,这个产品是怎么交到我们产品经理手上的呢? 中间很重要的就是工人,也就是操作符。它负责在Observable发出的事件和Observable的响应之间做一些处理。
首先我们来看一段Java代码:
static List<Student> studentList = new ArrayList<Student>(){
{
add(new Student("Stay", 28));
add(new Student("谷歌小弟", 23));
add(new Student("Star", 25));
}
};
List<Student> list = new ArrayList<Student>();
new Thread(new Runnable(){
@Override public void run(){
synchronized (studentList) {
for(Student student : studentList) {
if(student.age > 23){
list.add(student);
}
}
}
runOnUiThread(new Runnable() {
@Override
public void run() {
//UI显示过滤后的数据
displayUI(list);
}
});
}
}).start();
此段代码实现的是过滤数据,也就是统计年龄大于23的学生,并将过滤数据显示在UI上。
使用RxJava来实现(体验一下RxJava的链式结构):
Observable.from(studentList) //from可以理解为创建一个循环
.filter(new Func1<Student, Boolean>() {//filter代表根据规则过滤
@Override
public Boolean call(Student student) {
return student.age > 23; //过滤年龄大于23的学生
}
}).subscribeOn(Schedulers.newThread()) //任务在新线程里运行
.toList()
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Action1<List<Student>>() {
@Override
public void call(List<Student> list) {
//UI显示过滤后的数据
displayUI(list);
}
});
可以看到,代码减少了,而且逻辑也很清晰。
下面我们再看个复杂点的场景:找出SD卡所有的.png格式的文件。
String basePath = Environment.getExternalStorageDirectory().getPath();
File rootFile = new File(basePath);
Observable.just(rootFile)
.flatMap(new Func1<File, Observable<File>>() {
@Override
public Observable<File> call(File file) {//遍历文件夹
return listFiles(file);
}
})
.filter(new Func1<File, Boolean>() {//过滤图片,二级文件夹中的图片无法找出
@Override
public Boolean call(File file) {
return file.getName().endsWith(".png");
}
})
.map(new Func1<File, String>() {
@Override
public String call(File file) {
return file.getPath();
}
})
.toList()
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Subscriber<List<String>>() {
@Override
public void onCompleted() {
}
@Override
public void onError(Throwable e) {
}
@Override
public void onNext(List<String> list) {//返回png格式图片列表
//do something
}
});
其中,listFiles方法如下:
/**
* 递归查询目录中的文件
* @param f
* @return
*/
public static Observable<File> listFiles(final File f){
if(f.isDirectory()){
return Observable.from(f.listFiles()).flatMap(new Func1<File, Observable<File>>() {
@Override
public Observable<File> call(File file) {
/**如果是文件夹就递归**/
return listFiles(file);
}
});
} else {
/**filter操作符过滤,是文件就通知观察者**/
return Observable.just(f).filter(new Func1<File, Boolean>() {
@Override
public Boolean call(File file) {
return f.exists() && f.canRead() ;
}
});
}
}
从上面这段代码我们可以看到:虽然代码量看起来变复杂了,但是RxJava的实现是一条链式调用,没有任何的嵌套;整个实现逻辑看起来非常简洁清晰,这对我们的编程实现和后期维护是有巨大帮助的。特别是对于那些回调嵌套的场景。
有没有心动,喜欢上RxJava了呢?
/**
* 模拟从数据库获取课程列表
* @return
*/
private static List<String> getCoursesFromDatabase() {
List<String> courseList = new ArrayList<>();
courseList.add("美术");
courseList.add("体育");
courseList.add("音乐");
return courseList;
}
在RxJava中,just和from操作符可以把一个对象转换成Observable,上面的方法使用just改写:
private static Observable<List<String>> getAllCourses() {
return Observable.just(getCoursesFromDatabase());
}
不过这样改写会有个问题,只要调用getAllCourses方法就会运行getCoursesFromDatabase方法,那么就不能通过指定Schedules的方式实现异步查询了。
所以如果某个方法经常会被异步调用,我们往往会使用create来改写:
private static Observable<List<String>> getAllCourses() {
return Observable.create(new OnSubscribe<List<String>>() {
@Override
public void call(Subscriber<? super List<String>> subscriber) {
List<String> courseList = getCoursesFromDatabase();
subscriber.onNext(courseList);
subscriber.onCompleted();
}
});
}
在使用Create操作符时,getCoursesFromDatabase方法是写在OnSubscribe接口的call方法里。调用getAllCourses方法,getCoursesFromDatabase并不会马上运行。
getAllCourses(db)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Subscriber<String>(){...});
注意:
因为just(),from()这类创建Observable的操作符在创建之初,就已经存储了对象的值,而不是在被订阅的时候才创建。所以在我们订阅之前,getCoursesFromDatabase()方法就已经在开始执行了,这样就不能达到我们想要的效果。
RxJava中的操作符可以让你对数据流做任何操作。
将一系列的操作符链接起来就可以完成复杂的逻辑。代码被分解成一系列可以组合的片段。这就是响应式函数编程的魅力。用的越多,就会越多的改变你的编程思维。
另外,RxJava也使我们处理数据的方式变得更简单。在最后一个例子里,我们调用了两个API,对API返回的数据进行了处理,然后保存到磁盘。 但是我们的Subscriber并不知道这些,它只是认为自己在接收一个Observable<String>
对象。良好的封装性也带来了编 码的便利!
RxJava的强大性就来自于它所定义的操作符。
RxJava包含了大量的操作符。操作符的数量是有点吓人,但是很值得你去挨个看一下,这样你可以知道有哪些操作符可以使用。弄懂这些操作符可能会花一些时间,但是一旦弄懂了,你就完全掌握了RxJava的威力。
你甚至可以编写自定义的操作符!这篇blog不打算讨论自定义操作符,如果你想的话,请自行Google吧。
目前为止,我们已经接触了filter、just、create三个操作符,RxJava中还有更多的操作符,那么我们如何使用其他的操作符来改进我们的代码呢?不要着急,后面会分类学习RxJava的操作符。
原文:http://blog.csdn.net/jdsjlzx/article/details/54970380