RxJava 中的map与flatMap

1、map和flatMap都是接受一个函数作为参数(Func1)
2、map函数只有一个参数,参数一般是Func1,Func1的<I,O>I,O模版分别为输入和输出值的类型,实现Func1的call方法对I类型进行处理后返回O类型数据3、flatMap函数也只有一个参数,也是Func1,Func1的<I,O>I,O模版分别为输入和输出值的类型,实现Func1的call方法对I类型进行处理后返回O类型数据,不过这里O为Observable类型

举例说明

有二箱鸡蛋,每箱5个,现在要把鸡蛋加工成煎蛋,然后分给学生。

map做的事情 :把二箱鸡蛋分别加工成煎蛋,还是放成原来的两箱,分给2组学生;
flatMap做的事情:把二箱鸡蛋分别加工成煎蛋,然后放到一起【10个煎蛋】,分给10个学生;

map

先说 map,一个简单的例子 👇

Observable.create(new ObservableOnSubscribe<Integer>() {
    @Override
    public void subscribe(ObservableEmitter<Integer> emitter) throws Exception {
        emitter.onNext(1);
        emitter.onNext(2);
        emitter.onNext(3);
        emitter.onComplete();
    }
})
.map(new Function<Integer, String>() {
    @Override
    public String apply(Integer integer) throws Exception {
        Log.e(TAG,"开始净化处理");
        return integer.toString() + "号水源净化中 => 净化完毕";
    }
})
.subscribe(new Observer<String>() {
    @Override
    public void onNext(String s) {
        Log.e(TAG,"接收到净化完毕的水【" + s + "】");
    }

    @Override
    public void onSubscribe(Disposable d) {}
    @Override
    public void onError(Throwable e) {}
    @Override
    public void onComplete() {}
});

// Log日志:
// 开始净化处理
// 接收到净化完毕的水【1号水源净化中 => 净化完毕】
// 开始净化处理
// 接收到净化完毕的水【2号水源净化中 => 净化完毕】
// 开始净化处理
// 接收到净化完毕的水【3号水源净化中 => 净化完毕】
  • 非通俗定义:map 操作符对原始 Observable 发射对每一项数据应用一个你选择对函数,然后返回一个发射这些结果对 Observable

如上,清晰明了,将 1、2、3 水源进行净化处理,最终接收到处理完毕到水,map 相当于一个中介,onNext(1) 发送的可以是你以后项目中服务器端获取到的数据,通过 map 这个中介处理,处理后的数据发送到最终接收的地方(Observer 的 onNext 方法中)

当然可能就是以后项目中【先接收服务器端的数据(比如接收到 int 数据)】=>【经过 map 这个中介处理成你想要的数据(转成 String)】=>【更新到 UI 上(设置到 textView 上)】

flatMap

这里说 flatMap 👇

  • 非通俗定义:将一个发送事件的 Observable(被观察者) 变换为发送多个事件的 Observables,然后将他们发射的事件合并后放进一个单独的 Observable 里,需要注意的是 flatMap 并不保证事件顺序,也就是说转换之后的 Observables 的顺序不必与转换之前的序列的顺序一致
// 先是两个很简单的类
class ClassRoom {
    String classRoomName; // 教室的名字
    List<Student> list = new ArrayList<>(); // 教室中的学生列表
}
class Student {
    Student(String n) {
        this.name = n;
    }
    String name;// 学生的名字
}

// 添加简单的测试数据
List<ClassRoom> school = new ArrayList<>();
// 1班
ClassRoom c1 = new ClassRoom();
c1.classRoomName = "1班";
c1.list.add(new Student("学生A"));
c1.list.add(new Student("学生B"));
c1.list.add(new Student("学生C"));
c1.list.add(new Student("学生D"));

// 2班
ClassRoom c2 = new ClassRoom();
c2.classRoomName = "2班";
c2.list.add(new Student("学生E"));
c2.list.add(new Student("学生F"));
c2.list.add(new Student("学生G"));
c2.list.add(new Student("学生H"));

// 3班
ClassRoom c3 = new ClassRoom();
c3.classRoomName = "3班";
c3.list.add(new Student("学生I"));
c3.list.add(new Student("学生J"));
c3.list.add(new Student("学生K"));
c3.list.add(new Student("学生L"));

// 添加
school.add(c1);
school.add(c2);
school.add(c3);

// 关键部分
Observable.fromIterable(school)
    .flatMap(new Function<ClassRoom, ObservableSource<Student>>() {
        @Override
        public ObservableSource<Student> apply(ClassRoom classRoom) throws Exception {
            Log.e(TAG, "ClassRoom name:" + classRoom.classRoomName);
            return Observable.fromIterable(classRoom.list).delay(10, TimeUnit.MILLISECONDS);
        }
    })
    .subscribe(new Observer<Student>() {
        @Override
        public void onNext(Student student) {
            Log.e(TAG, "学生姓名:" + student.name);
        }

        @Override
        public void onSubscribe(Disposable d) {}
        @Override
        public void onError(Throwable e) {}
        @Override
        public void onComplete() {}
    });

首先 fromIterable 是什么:相当于 👇

onNext(school.get(0));
onNext(school.get(1));
onNext(school.get(2));
onComplete();

那么 Observable.fromIterable(classRoom.list).delay(10, TimeUnit.MILLISECONDS); 是什么?相当于原有的基础上在发送之前加了 10 毫秒的延迟,TimeUnit 表示事件单位,这里用的是 MILLISECONDS 也就是毫秒,秒则是 SECONDS,这里加一个延迟主要是为了模拟网络延迟的效果

看一下日志

// 加了 10 毫秒延迟的
ClassRoom name:1班
ClassRoom name:2班
ClassRoom name:3班
学生姓名:学生A
学生姓名:学生C
学生姓名:学生B
学生姓名:学生E
学生姓名:学生D
学生姓名:学生G
学生姓名:学生F
学生姓名:学生H
学生姓名:学生J
学生姓名:学生K
学生姓名:学生I
学生姓名:学生L

// 不加延迟的
ClassRoom name:1班
学生姓名:学生A
学生姓名:学生B
学生姓名:学生C
学生姓名:学生D
ClassRoom name:2班
学生姓名:学生E
学生姓名:学生F
学生姓名:学生G
学生姓名:学生H
ClassRoom name:3班
学生姓名:学生I
学生姓名:学生J
学生姓名:学生K
学生姓名:学生L

可以看到,就像上面 非通俗定义 中所说的并不保证事件的顺序(A、C、B、E、D、G...),加延迟主要是为了更好的显现出它不保证顺序的特性,并不是因为有了延迟才不保证顺序,而是无论如何 flatMap 都不保证你接收到事件的顺序

我们这个例子相当于 一个学校 中有 3 个班级,我们想要打印出所有 班级的名字 以及 每个班级每个学生的名字,但是你可能会看到觉得代码反而变多了

  • 首先这只是个例子
  • RxJava 并不是说让代码变少,而是让代码逻辑更清晰,试想清晰的代码逻辑和少又难懂又嵌套了各种循环的代码那个更好呢
  • 当你了解的操作符多了,在项目中遇到实际问题你自然知道哪个最适合你

通过这个例子可以看出,flatMap 是将发送事件的 Observable 经过 flatMap 变换为多个发送事件的 Observables 然后再将他们发射后的事件合并后放进一个单独的 Observable 里,看下图 👇
在这里插入图片描述

再来看更加详细的分解 👇

在这里插入图片描述

由上图再根据我们的例子得知:c1、c2、c3 经过 flatMap 后,依次经历了 Observable1、2、3(图中椭圆形的内容),打印了一下班级名,然后又分别把他们转换为了 StudentA - StudentL,其中 StudentA - StudentDc1 得到,以此类推。

想必此时已经清晰明了了,当然现在你已经知道 flatMap 并不保证事件的顺序,如果想要保证顺序的话需要使用 concatMap

使用场景

map 适用于一对一转换

flatMap 适用于一对多,多对多

  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值