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

来源:互联网 发布:windows xp升级win10 编辑:程序博客网 时间:2024/04/29 01:14

如果你对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
原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 狗狗洗澡后拉稀怎么办 狗狗好像生病了怎么办 奶狗前腿断了怎么办 狗摔了一下瘸了怎么办 小狗腿突然瘸了怎么办 狗腿突然瘸了怎么办 狗腿受伤了肿了怎么办 狗狗缺钙腿变形怎么办 小狗腿摔骨折了怎么办 狗狗脚掌被压了怎么办 狗狗的脚骨折了怎么办 给猫灌药水呛到怎么办 吃佐匹克隆白天工作量降低怎么办? 手机网页不显示图片怎么办啊 页眉页脚同前节怎么办 小米8后盖缝隙大怎么办 狗子生了一个不动的小狗怎么办 狗狗肚子有脓包怎么办 小孩幼儿园数学不开窍怎么办 老百姓打仗了报警派出所不管怎么办 和人打架报案了怎么办 皇上死后的妃子怎么办 武警改制警卫系的学员怎么办 正团病故后住房怎么办 遇到保姆式领导该怎么办 限购房子卖不了怎么办 斑马线礼让行人行人不走怎么办 中国留学生签证在美国被取消怎么办 建行卡网银帐号密码输入错误怎么办 建行卡密码忘了怎么办? 银行卡k宝丢了怎么办 k宝密码锁住了怎么办 农业银行k宝锁了怎么办 银行卡办的网银卡丢了怎么办 事业单位考察档案丢了怎么办 当兵政审家访家里没人在家怎么办 士兵转业结婚材料不全怎么办 体育生训练腿疼怎么办 车底盘刮的严重怎么办 新车底盘被刮了怎么办 车侧面刮凹了怎么办