RxJava从入门到不离不弃(三)——转换操作符

前面两篇文章中我们介绍了RxJava的一些基本概念和RxJava最简单的用法。从这一篇开始,我们开始聊聊RxJava中的操作符Operators。

RxJava中的操作符主要分成了三类:

  • 转换类操作符(map flatMap concatMap flatMapIterable switchMap scan groupBy …);
  • 过滤类操作符(fileter take takeLast takeUntil distinct distinctUntilChanged skip skipLast …);
  • 组合类操作符(merge zip join combineLatest and/when/then switch startSwitch …)。

这一篇主要介绍几个常用的转换操作符——map、flatMapgroupBy

所有这些Operators都作用于一个可观测序列,然后变换它发射的值,最后用一种新的形式返回它们。概念实在是不好理解,下面我们结合实际的例子一一介绍。

map

map操作符,就是用来把把一个事件转换为另一个事件的。map()操作符就是用于变换Observable对象的,map操作符返回一个Observable对象,这样就可以实现链式调用,在一个Observable对象上多次使用map操作符,最终将最简洁的数据传递给Subscriber对象。

看个例子:

Observable.from(list)
        .map(new Func1<Person, Person>() {
            @Override
            public Person call(Person person) {
                if (person.getAge() % 2 == 0)
                    person.setName("js");
                return person;
            }
        })
        .subscribe(new Action1<Person>() {
            @Override
            public void call(Person person) {
                Log.e("map", "call: " + person.toString());
            }
        });

上面的例子,发射源发射一个Person数据集合,然后执行map操作,将数据集合中的数据,判断如果年龄是偶数,就将其名字改为“js”,然后返回,最终观察者中打印。

这个例子只是简单的解释map操作符的作用,其核心就是将数据进行转换,数据转换在map操作符的Func1中实现,Func1第一个泛型是传入类型,第二个泛型是输出类型,在call方法中实现转换,当然传入类型和输出类型完全可以不同。

再看个例子:

Observable.just("images/logo.png") // 输入类型 String
        .map(new Func1<String, Bitmap>() {
            @Override
            public Bitmap call(String filePath) { // 参数类型 String
                return getBitmapFromPath(filePath); // 返回类型 Bitmap
            }
        })
        .subscribe(new Action1<Bitmap>() {
            @Override
            public void call(Bitmap bitmap) { // 参数类型 Bitmap
                showBitmap(bitmap);
            }
        });

这个例子就更贴合实际开发了,发射器发射一个图片地址,在map操作符中根据图片地址加载返回Bitmap对象交给接收器,在接收器中接受Bitmap进行展示。

当然,进行图片加载和图片展示应该分别位于子线程和主线程中执行,这里就用到了RxJava的线程调度器,这个之后再介绍。这里只是展示map操作符的用法和作用。

可以看出:

map() 方法将参数中的 String 对象转换成一个 Bitmap 对象后返回,而在经过 map() 方法后,事件的参数类型也由 String 转为了 Bitmap。这种直接变换对象并返回的,是最常见的也最容易理解的变换。不过 RxJava 的变换远不止这样,它不仅可以针对事件对象,还可以针对整个事件队列,这使得 RxJava 变得非常灵活。

flatMap

map适用于一对一转换,当然也可以配合flatmap进行适用,flatmap适用于一对多,多对多的场景。

先从一个例子入手:

List<Student> students = new ArrayList<>();
for (int i = 0; i < 3; i++) {
    Student student = new Student();
    List<Student.Course> courses = new ArrayList<>();
    for (int j = 0; j < 6; j++) {
        Student.Course course = new Student.Course("课程" + j);
        courses.add(course);
    }
    student.setList(courses);
    students.add(student);
}


Observable.from(students)
        .flatMap(new Func1<Student, Observable<Student.Course>>() {
            @Override
            public Observable<Student.Course> call(Student student) {
                return Observable.from(student.getList());
            }
        })
        .subscribe(new Action1<Student.Course>() {
            @Override
            public void call(Student.Course r) {
                Log.e("flatMap", "call: " + r.toString());
            }
        });

现在有一个学生集合,每个学生又都有一个课程集合,业务要求将每个学生所选的每个课程全部打印,我们就可以使用flatMap操作符。

原始发射源发射学生集合,在flatMap操作符中获取学生对应的课程集合,再将其转换为一个新的Observable对象返回,最终接收器中打印课程。根据输出结果可以发现,转换后的发射源发射集合,接收器中逐个打印,接下来原始反射器发射第二个学生对象,再执行flatMap转换为新的Observable对象,再逐个打印该学生的所有课程对象。。。

map与flatMap的区别:

  1. map返回的是结果集,flatmap返回的是包含结果集的Observable(返回结果不同)。
  2. map被订阅时每传递一个事件执行一次onNext方法, flatmap多用于多对多,一对多,再被转化为多个时,一般利用from/just进行一一分发。被订阅时将所有数据传递完毕汇总到一个Observable然后一一执行onNext方法(执行顺序不同)。
  3. map只能单一转换,单一指的是只能一对一进行转换,指一个对象可以转化为另一个对象但是不能转换成对象数组;map返回结果集不能直接使用from/just再次进行事件分发,一旦转换成对象数组的话,再处理集合/数组的结果时需要利用for一一遍历取出,而使用RxJava就是为了剔除这样的嵌套结构,使得整体的逻辑性更强。)flatmap既可以单一转换也可以一对多/多对多转换,flatmap要求返回Observable,因此可以再内部进行from/just的再次事件分发,一一取出单一对象(转换对象的能力不同)。

groupBy

groupBy顾名思义就是分组的意思。

将一个Observable分拆为一些Observables集合,它们中的每一个发射原始Observable的一个子序列,GroupBy操作符将原始Observable分拆为一些Observables集合,它们中的每一个发射原始Observable数据序列的一个子序列。哪个数据项由哪一个Observable发射是由一个函数判定的,这个函数给每一项指定一个Key,Key相同的数据会被同一个Observable发射。

Observable from = Observable.from(list);
from.groupBy(new Func1<Object,Integer>() {
    @Override
    public Integer call(Object o) {
        String name = o.getClass().getName();
        String a = A.class.getName();
        String b = B.class.getName();
        String c = C.class.getName();
        if (name.equals(a)){
            return  1;
        }else if(name.equals(b)){
            return  2;
        }else if(name.equals(c)){
            return  3;
        }
            return 4;
        }
})
.subscribe(new Action1<GroupedObservable<Integer,Object>>() {
    @Override
    public void call(GroupedObservable<Integer,Object> objectIntegerGroupedObservable) {
        int sign = objectIntegerGroupedObservable.getKey();

        switch (sign){
             case 1:
                objectIntegerGroupedObservable.subscribe(new Action1<Object>() {
                    @Override
                    public void call(Object a) {
                        Log.d("groupby","class A - "+a.getClass().getName());
                    }
                });
                break;
              case 2:
                 objectIntegerGroupedObservable.subscribe(new Action1<Object>() {
                    @Override
                    public void call(Object a) {
                        Log.d("groupby","class B - "+a.getClass().getName());
                    }
                  });
                  break;
              case 3:
                 objectIntegerGroupedObservable.subscribe(new Action1<Object>() {
                    @Override
                    public void call(Object a) {
                        Log.d("groupby","class C - "+a.getClass().getName());
                    }
                  });
                  break;
               default:
                  Log.d("groupby","other class");
                  break;
            }
        }
});

实践出真知 先构造了三个类A,B,C,用一个List装了他们的若干个实例,随机的,再使用Observer发射出去,经过GroupBy的作用后打印结果。

在GroupBy的Func1()函数中按你的逻辑分组,并将每个信息对应的组的key标志返回,如例子中我个标志都是Integer类型的,GroupBy会返回Observable的一个特殊子类GroupedObservable,这个特殊子类有个额外的方法getKey(),可用于获得当前信息的组别。

ok,RxJava的转换操作符就下你介绍到这里,更多精彩内容,欢迎关注我的微信公众号——Android机动车

本文分享自微信公众号 - Android机动车(JsAndroidClub)

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2018-07-16

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏FSociety

SQL中GROUP BY用法示例

GROUP BY我们可以先从字面上来理解,GROUP表示分组,BY后面写字段名,就表示根据哪个字段进行分组,如果有用Excel比较多的话,GROUP BY比较类...

5.1K20
来自专栏腾讯社交用户体验设计

ISUX Xcube智能一键生成H5

50920
来自专栏钱塘大数据

理工男图解零维到十维空间,烧脑已过度,受不了啦!

让我们从一个点开始,和我们几何意义上的点一样,它没有大小、没有维度。它只是被想象出来的、作为标志一个位置的点。它什么也没有,空间、时间通通不存在,这就是零维度。

28430
来自专栏钱塘大数据

中国互联网协会发布:《2018中国互联网发展报告》

在2018中国互联网大会闭幕论坛上,中国互联网协会正式发布《中国互联网发展报告2018》(以下简称《报告》)。《中国互联网发展报告》是由中国互联网协会与中国互联...

13450
来自专栏haifeiWu与他朋友们的专栏

复杂业务下向Mysql导入30万条数据代码优化的踩坑记录

从毕业到现在第一次接触到超过30万条数据导入MySQL的场景(有点low),就是在顺丰公司接入我司EMM产品时需要将AD中的员工数据导入MySQL中,因此楼主负...

27640
来自专栏微信公众号:小白课代表

不只是软件,在线也可以免费下载百度文库了。

不管是学生,还是职场员工,下载各种文档几乎是不可避免的,各种XXX.docx,XXX.pptx更是家常便饭,人们最常用的就是百度文库,豆丁文库,道客巴巴这些下载...

44030
来自专栏Ken的杂谈

【系统设置】CentOS 修改机器名

17830
来自专栏前端桃园

知识体系解决迷茫的你

最近在星球里群里都有小伙伴说道自己对未来的路比较迷茫,一旦闲下来就不知道自己改干啥,今天我这篇文章就是让你觉得一天给你 25 个小时你都不够用,觉得睡觉都是浪费...

20140
来自专栏腾讯大讲堂的专栏

白底黑字or黑底白字,眼睛更喜欢哪一个?

12010
来自专栏怀英的自我修炼

考研英语-1-导学

英二图表作文要重视。总体而言,英语一会比英语二难点。不过就写作而言,英语二会比英语一有难度,毕竟图表作文并不好写。

11510

扫码关注云+社区

领取腾讯云代金券

年度创作总结 领取年终奖励