RxJava的map方法与flatMap方法
简单讲,map和flatMap都是来完成Observable构造的数据到Observer接收数据的一个转换,这么说有点绕😋,直接看Demo。
第一步,我们构造数据结构:
构造一个课程:
1 package com.plbear.doncal.rxjavademo; 2 3 public class Course { 4 private String name; 5 6 public Course(String name) { 7 this.name = name; 8 } 9 10 public String getName() { 11 return name; 12 } 13 14 @Override 15 public String toString() { 16 return super.toString(); 17 } 18 }
构造学生,一个学生可以选择多门课程:
1 package com.plbear.doncal.rxjavademo; 2 3 import java.util.ArrayList; 4 import java.util.List; 5 6 public class Student { 7 private String name; 8 private List<Course> courseList = new ArrayList<>(); 9 10 public String getName() { 11 return name; 12 } 13 14 public List<Course> getCourseList() { 15 return courseList; 16 } 17 18 public void setCourseList(List<Course> courseList) { 19 this.courseList = courseList; 20 } 21 22 public void setName(String name) { 23 this.name = name; 24 } 25 }
接下来初始化数据:
1 List<Course> courses1 = new ArrayList<>(); 2 3 courses1.add(new Course("1")); 4 courses1.add(new Course("2")); 5 courses1.add(new Course("3")); 6 7 Student student1 = new Student(); 8 student1.setName("student1"); 9 student1.setCourseList(courses1); 10 11 List<Course> courses2 = new ArrayList<>(); 12 13 courses2.add(new Course("4")); 14 courses2.add(new Course("5")); 15 courses2.add(new Course("6")); 16 17 Student student2 = new Student(); 18 student2.setName("student2"); 19 student2.setCourseList(courses2); 20 List<Student> students = new ArrayList<>(); 21 students.add(student1); 22 students.add(student2);
第二步:如果不用map或者flatMap,打印所有学生的课程?
1 rx.Observable.from(students) 2 .observeOn(AndroidSchedulers.mainThread()) 3 .subscribe(new Subscriber<Student>() { 4 @Override 5 public void onCompleted() { 6 log("onCompleted"); 7 } 8 9 @Override 10 public void onError(Throwable e) { 11 log("onError"); 12 } 13 14 @Override 15 public void onNext(Student student) { 16 for (int i = 0; i < student.getCourseList().size(); i++) { 17 log("onNext:" + student.getCourseList().get(i).getName()); 18 } 19 } 20 });
输出如下:
1 10-16 18:12:21.266 19369 19369 E MainActivity: yanlog msg:onNext:1 2 10-16 18:12:21.266 19369 19369 E MainActivity: yanlog msg:onNext:2 3 10-16 18:12:21.266 19369 19369 E MainActivity: yanlog msg:onNext:3 4 10-16 18:12:21.266 19369 19369 E MainActivity: yanlog msg:onNext:4 5 10-16 18:12:21.267 19369 19369 E MainActivity: yanlog msg:onNext:5 6 10-16 18:12:21.267 19369 19369 E MainActivity: yanlog msg:onNext:6 7 10-16 18:12:21.267 19369 19369 E MainActivity: yanlog msg:onCompleted
如上面代码所示,我们使用Observable.from依次发射数据,发射的数据类型是student。但是我需要打印的是课程名啊,能否接收课程名呢?
第三步:使用map来转换
直接上代码:
1 rx.Observable.from(students) 2 .map(new Func1<Student, List<Course>>() { 3 @Override 4 public List<Course> call(Student student) { 5 return student.getCourseList(); 6 } 7 }) 8 .observeOn(AndroidSchedulers.mainThread()) 9 .subscribe(new Subscriber<List<Course>>() { 10 @Override 11 public void onCompleted() { 12 log("onCompleted"); 13 } 14 15 @Override 16 public void onError(Throwable e) { 17 log("onError"); 18 } 19 20 @Override 21 public void onNext(List<Course> courses) { 22 for (int i = 0; i < courses.size(); i++) { 23 log("onNext:" + courses.get(i).getName()); 24 } 25 } 26 });
如果你喜欢Lamba表达式的话,也可以这样:
1 rx.Observable.from(students) 2 .map(student -> student.getCourseList()) 3 .observeOn(AndroidSchedulers.mainThread()) 4 .subscribe(new Subscriber<List<Course>>() { 5 @Override 6 public void onCompleted() { 7 log("onCompleted"); 8 } 9 10 @Override 11 public void onError(Throwable e) { 12 log("onError"); 13 } 14 15 @Override 16 public void onNext(List<Course> courses) { 17 for (int i = 0; i < courses.size(); i++) { 18 log("onNext:" + courses.get(i).getName()); 19 } 20 } 21 });
看执行结果:
1 10-16 18:39:09.740 22392 22392 E MainActivity: yanlog msg:over 2 10-16 18:39:09.861 22392 22392 E MainActivity: yanlog msg:onNext:1 3 10-16 18:39:09.861 22392 22392 E MainActivity: yanlog msg:onNext:2 4 10-16 18:39:09.861 22392 22392 E MainActivity: yanlog msg:onNext:3 5 10-16 18:39:09.861 22392 22392 E MainActivity: yanlog msg:onNext:4 6 10-16 18:39:09.861 22392 22392 E MainActivity: yanlog msg:onNext:5 7 10-16 18:39:09.861 22392 22392 E MainActivity: yanlog msg:onNext:6 8 10-16 18:39:09.861 22392 22392 E MainActivity: yanlog msg:onCompleted
第四步:使用flatMap来转换
我们发现使用map之后,代码还是不够简单,里面有一个for循环结构,而RxJava实际上是要避免这种for循环结构的。那我们利用flatMap来看下:
1 rx.Observable.from(students) 2 .flatMap(new Func1<Student, rx.Observable<Course>>() { 3 @Override 4 public rx.Observable<Course> call(Student student) { 5 return rx.Observable.from(student.getCourseList()); 6 } 7 }) 8 .observeOn(AndroidSchedulers.mainThread()) 9 .subscribe(new Subscriber<Course>() { 10 @Override 11 public void onCompleted() { 12 log("onCompleted"); 13 } 14 15 @Override 16 public void onError(Throwable e) { 17 log("onError"); 18 } 19 20 @Override 21 public void onNext(Course courses) { 22 log("onNext"+courses); 23 } 24 });
同样,我们给出lamba的实现:
1 rx.Observable.from(students) 2 .flatMap(student -> rx.Observable.from(student.getCourseList())) 3 .observeOn(AndroidSchedulers.mainThread()) 4 .subscribe(new Subscriber<Course>() { 5 @Override 6 public void onCompleted() { 7 log("onCompleted"); 8 } 9 10 @Override 11 public void onError(Throwable e) { 12 log("onError"); 13 } 14 15 @Override 16 public void onNext(Course courses) { 17 log("onNext"+courses); 18 } 19 });
看一下输出结果:
1 10-16 18:46:32.511 23190 23190 E MainActivity: yanlog msg:over 2 10-16 18:46:32.647 23190 23190 E MainActivity: yanlog msg:onNext1 3 10-16 18:46:32.647 23190 23190 E MainActivity: yanlog msg:onNext2 4 10-16 18:46:32.647 23190 23190 E MainActivity: yanlog msg:onNext3 5 10-16 18:46:32.648 23190 23190 E MainActivity: yanlog msg:onNext4 6 10-16 18:46:32.648 23190 23190 E MainActivity: yanlog msg:onNext5 7 10-16 18:46:32.648 23190 23190 E MainActivity: yanlog msg:onNext6 8 10-16 18:46:32.649 23190 23190 E MainActivity: yanlog msg:onCompleted
从上面可以看到,flatMap实际上是将一个Observable对象分拆成两个,然后再依次发送出去,从而达到可以去掉for循环,优化结构的目的。