• RxJava学习笔记(操作符)


    前言

    上一篇文章介绍了RxJava的基础知识和简单实现,篇幅已经比较多了,所以把操作符(Operators)相关的内容放在这一篇。有了上一篇文章的基础,相信会比较容易理解操作符相关的内容了。

    操作符(Operators)

    拿上一篇文章中的例子HelloWorld为例

    1
    2
    3
    4
    5
    6
    7
    8

    Observable.just("HelloWorld").subscribe(new Action1<String>() {

    public void (String s) {
    Log.d(LOG_TAG, s);
    }
    });

    如果希望在输出的字符串后面加上特定字符,比如说”***”,这时候如果我们可以修改Observable对象,那么可以直接在后面加上拼接字符串,程序如下所示

    1
    2
    3
    4
    5
    6
    7
    8

    Observable.just("HelloWorld***").subscribe(new Action1<String>() {

    public void (String s) {
    Log.d(LOG_TAG, s);
    }
    });

    但是,如果我们不可以修改Observable对象呢,比如说它是由第三方库提供的呢?或者,这个Observable被多个Observer对象订阅,但是我们只想针对某个Observer做修改呢?这时候可以在Observer中进行修改,程序如下所示

    1
    2
    3
    4
    5
    6
    7
    8
    9

    Observable.just("HelloWorld").subscribe(new Action1<String>() {

    public void (String s) {
    Log.d(LOG_TAG, s + "***");
    }
    });


    这种方式,看似解决了问题,但是仍然是不够的,此时的Observer不够轻量,根据响应式函数编程的概念,Observer应该做的事情是”响应“,响应Observable发出的事件,而不是修改。如果我们能在Observable发出事件之后,Observer订阅事件之前对“HelloWorld”进行变换,那不就好了!

    map操作符

    RxJava里面,提供了操作符,用于解决Observable对象变换的问题,用于在Observable和Observer之间修改Observable发出的事件,map操作符就是把一个事件转换成另外一个事件的,程序如下所示

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13

    Observable.just("HelloWorld").map(new Func1<String, String>() {

    public String (String s) {
    return s + "***";
    }
    }).subscribe(new Action1<String>() {

    public void (String s) {
    Log.d(LOG_TAG, s);
    }
    });

    上面的程序中,转换前后的Observable对象类型是相同的,如果,我们能做到转换前后的数据类型是不同的,是不是会更加酷呢?比如说,Observer不关心返回的字符串,而是想要字符串的hash值,那么就可以这么做

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13

    Observable.just("HelloWorld").map(new Func1<String, Integer>() {
    @Override
    public Integer call(String s) {
    return s.hashCode();
    }
    }).subscribe(new Action1<Integer>() {
    @Override
    public void call(Integer integer) {
    Log.d(LOG_TAG, Integer.toString(integer));
    }
    });

    太酷了,我们初始化Observable对象返回的是字符串,最终Observer获取的是Integer。如果简化一下Observer,我们可以再增加一个map操作符,程序如下

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18

    Observable.just("HelloWorld").map(new Func1<String, Integer>() {
    @Override
    public Integer call(String s) {
    return s.hashCode();
    }
    }).map(new Func1<Integer, String>() {
    @Override
    public String call(Integer integer) {
    return Integer.toString(integer);
    }
    }).subscribe(new Action1<String>() {
    @Override
    public void call(String s) {
    Log.d(LOG_TAG, s);
    }
    });

    代码量虽然变多了,但是程序变得更加简洁!

    from操作符

    这时候,如果我们要发出的事件不再是一个字符串,而是一个字符串列表,如果用现有的知识,程序如下

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10

    Observable.just(stringList).subscribe(new Action1<List<String>>() {
    @Override
    public void call(List<String> strings) {
    for (String s : strings) {
    Log.d(LOG_TAG, s);
    }
    }
    });

    这种代码是比较糟糕的,因为在我们的Observer中竟然要做for循环这种复杂的操作,有没有办法简化呢?这时候,from操作符可以帮到我们,程序如下

    1
    2
    3
    4
    5
    6
    7
    8

    Observable.from(stringList).subscribe(new Action1<String>() {
    @Override
    public void call(String s) {
    Log.d(LOG_TAG, s);
    }
    });

    现在的程序看起来很好,for循环消失了,因为from操作符就是用来接收一个集合,然后每次输出一个元素给Observer的!这时,如果我们还要做事件对象的变换,可以这样

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    大专栏  RxJava学习笔记(操作符)">11
    12
    13

    Observable.from(stringList).map(new Func1<String, Integer>() {
    @Override
    public Integer call(String s) {
    return s.hashCode();
    }
    }).subscribe(new Action1<Integer>() {
    @Override
    public void call(Integer integer) {
    Log.d(LOG_TAG, Integer.toString(integer));
    }
    });

    简洁明了,看着舒服,哈哈!
    现在有一个需求,有教师这样的一个数据结构,里面有名字name和课程列表courseList,现在要打印一组老师的名字,程序如下

    1
    2
    3
    4
    5
    6
    7
    8

    Observable.from(teacherList).subscribe(new Action1<Teacher>() {
    @Override
    public void call(Teacher teacher) {
    Log.d(LOG_TAG, teacher.getName());
    }
    });

    flatMap操作符

    实现很简单,那么再有一个需求,要打印出每个教师所教授的课程名称呢?(两个需求的区别在于,每个教师只有一个名字,但是可以教授多门课程),我们首先可能会这么写

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10

    Observable.from(teacherList).subscribe(new Action1<Teacher>() {
    @Override
    public void call(Teacher teacher) {
    for (Course course : teacher.getCourseList()) {
    Log.d(LOG_TAG, course.getCourseName());
    }
    }
    });

    同样的问题又来了,我们的Observer不够轻量,在里面做了for循环的操作,而且,这时候map和from操作符也不能解决问题,因为map做的是一对一的变换,所以flatMap出场了,程序如下

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13

    Observable.from(teacherList).flatMap(new Func1<Teacher, Observable<Course>>() {
    @Override
    public Observable<Course> call(Teacher teacher) {
    return Observable.from(teacher.getCourseList());
    }
    }).subscribe(new Action1<Course>() {
    @Override
    public void call(Course course) {
    Log.d(LOG_TAG, course.getCourseName());
    }
    });

    代码又重新变得简洁明了,实现了一个teacher到多个Course对象的变换!这里需要注意一下,虽然map和flatMap操作符都是把传入参数转换后返回另一个对象,但是flatMap操作符返回的是Observable对象,并且这个 Observable 对象并不是被直接发送到了Observer的回调方法中!flatMap的原理:

    • 使用传入的事件对象创建一个Observable对象
    • 将这个新的Observable对象激活,于是事件由这个新的对象发出
    • 每一个创建出来的Observable对象发送的事件,都被汇入同一个Observable,而这个Observable负责将这些事件统一交给Observer的回调方法

    其它操作符

    到目前为止,我们已经接触了map、from、flatMap等强大而且常用的操作符,但是RxJava中还有很多其它的操作符:

    filter操作符

    比如说我们在输出课程名字的时候,不想输出数学这门科目,我们可以这么做

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18

    Observable.from(teacherList).flatMap(new Func1<Teacher, Observable<Course>>() {
    @Override
    public Observable<Course> call(Teacher teacher) {
    return Observable.from(teacher.getCourseList());
    }
    }).filter(new Func1<Course, Boolean>() {
    @Override
    public Boolean call(Course course) {
    return !course.equals("数学");
    }
    }).subscribe(new Action1<Course>() {
    @Override
    public void call(Course course) {
    Log.d(LOG_TAG, course.getCourseName());
    }
    });

    filter操作符会输入和输出相同的对象,并且可以过滤掉不满足条件的。

    take操作符

    比如说我们在输出课程的时候,课程可能会有很多,我们只想最多输出五门课程,我们可以这么做

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19

    Observable.from(teacherList).flatMap(new Func1<Teacher, Observable<Course>>() {
    @Override
    public Observable<Course> call(Teacher teacher) {
    return Observable.from(teacher.getCourseList());
    }
    }).filter(new Func1<Course, Boolean>() {
    @Override
    public Boolean call(Course course) {
    return !course.equals("数学");
    }
    }).take(5)
    .subscribe(new Action1<Course>() {
    @Override
    public void call(Course course) {
    Log.d(LOG_TAG, course.getCourseName());
    }
    });

    当然了,RxJava还有很多好用的操作符,要知道Observable这个类可是有九千多,接近一万行代码呢,更多的内容,就不在这里记录了。

    参考文章

  • 相关阅读:
    网页连接无法打开可运行
    SET XACT_ABORT
    用Windows Live Writer写CSDN博客的步骤
    ATO,PTO
    什么是贸易顺差?
    ATO/MTO类机械制造业特点以及ERP需求分析(二)
    如何在早期版本的 Office 中打开并保存 Word 2007、Excel 2007 和 PowerPoint 2007 文件
    Alpha和Beta测试简介
    IIS6.0下 Asp网页访问出现500的问题
    合格的程序员
  • 原文地址:https://www.cnblogs.com/lijianming180/p/12227165.html
Copyright © 2020-2023  润新知