在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了呢?
在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的操作符。
新闻热点
疑难解答