RxJava的车间操作工人-操作符

来源:互联网 发布:windows xp升级win10 编辑:程序博客网 时间:2024/06/02 15:52

如果你对RxJava1.x还不是了解,可以参考下面文章。

1. RxJava使用介绍 【视频教程】
2. RxJava操作符
  • Creating Observables(Observable的创建操作符) 【视频教程】
  • Transforming Observables(Observable的转换操作符) 【视频教程】
  • Filtering Observables(Observable的过滤操作符) 【视频教程】
  • Combining Observables(Observable的组合操作符) 【视频教程】
  • Error Handling Operators(Observable的错误处理操作符) 【视频教程】
  • Observable Utility Operators(Observable的辅助性操作符) 【视频教程】
  • Conditional and Boolean Operators(Observable的条件和布尔操作符) 【视频教程】
  • Mathematical and Aggregate Operators(Observable数学运算及聚合操作符) 【视频教程】
  • 其他如observable.toList()、observable.connect()、observable.publish()等等; 【视频教程】
3. RxJava Observer与Subcriber的关系 【视频教程】
4. RxJava线程控制(Scheduler) 【视频教程】
5. RxJava 并发之数据流发射太快如何办(背压(Backpressure)) 【视频教程】


在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了呢?

将非Rx方法转换成Rx方法

/** * 模拟从数据库获取课程列表 * @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的操作符。

3 0
原创粉丝点击