RxJava2系列第三篇---操作符

目錄

第一篇---基本使用
第二篇---異步
第一篇---操作符

RxJava提供了大量操作符,本文主要列一些常用到的操作符

1. 創建類型

create
Observable.create(new ObservableOnSubscribe<String>() {
  @Override
  public void subscribe(ObservableEmitter<String> emitter) throws Exception {
    emitter.onNext("1");
  }
});
just
Observable.just(1).subscribe(new Consumer<Integer>() {
  @Override
  public void accept(Integer integer) throws Exception {

  }
});
fromArray
Observable.fromArray(1).subscribe(new Consumer<Integer>() {
  @Override
  public void accept(Integer integer) throws Exception {
    
  }
});
fromCallable
Observable.fromCallable(new Callable<String>() {
  @Override
  public String call() throws Exception {
    return "1";
  }
});
它們之間的區別
  • create需要主動調用onNext來發送事件,這樣下游才能接收到事件
  • just用于發送有限個事件(1到9個),fromArray用于發送數組類型的事件集

2. 轉換型

map
map事件流向.png

圖中map的作用就是將上游的圓形事件轉化成了矩形事件,下面來看看代碼例子

 Observable.create(new ObservableOnSubscribe<String>() {
        @Override
        public void subscribe(ObservableEmitter<String> emitter) throws Exception {
            emitter.onNext("1");
        }
    }).map(new Function<String, Integer>() {
        @Override
        public Integer apply(String s) throws Exception {
            return Integer.valueOf(s);
        }
    }).subscribe(new Consumer<Integer>() {
        @Override
        public void accept(Integer integer) throws Exception {
            Log.d("TAG","integer:"+integer);
        }
    });

結果輸出

D/TAG: integer:1

結果分析
上游我們發送了一個String類型的數據
下游我們收到的是一個Integer類型的數據
map的作用就是將上游的數據轉化成下游所需要的任意類型

flatMap
flatMap流向圖.png

flatMap與map的區別
map只能處理一對一的轉換,而flatMap可以處理一對多,多對多的轉換
map直接返回的是要轉化的類型,flatMap返回的是Observable對象,這將相當于創建了一個新的管道,下游收到的將是這個管道的東西。

舉個栗子
在舉例子之前,我們先看一段代碼,來看看Observable的的create,just,fromXXX的區別

String[] courses={"數據結構","操作系統","算法導論"};
String[] students={"王二","張三","李四"};

    List<Course> courseList=new ArrayList<>();
    for(int i=0;i<courses.length;i++){
        Course course=new Course();
        course.name=courses[I];
        courseList.add(course);
    }

    List<Student> studentList=new ArrayList<>();
    for(int i=0;i<students.length;i++){
        Student student=new Student();
        student.name=students[I];
        student.courseList=courseList;
        studentList.add(student);
    }

    
    Observable.create(new ObservableOnSubscribe<Student>() {
        @Override
        public void subscribe(ObservableEmitter<Student> emitter) throws Exception {

        }
    }).subscribe(new Consumer<Student>() {
        @Override
        public void accept(Student student) throws Exception {
            Log.d("TAG","create");
        }
    });

    Observable.just(studentList).subscribe(new Consumer<List<Student>>() {
        @Override
        public void accept(List<Student> students) throws Exception {
            Log.d("TAG","just");
        }
    });
    

    Observable.fromIterable(studentList).subscribe(new Consumer<Student>() {
        @Override
        public void accept(Student students) throws Exception {
            Log.d("TAG","fromIterable");
        }
    });

輸出結果

D/TAG: just
D/TAG: fromIterable
D/TAG: fromIterable
D/TAG: fromIterable

結果分析
create沒有輸出,是因為沒有主動調用next事件
create只能傳遞單對象,如果是事件集,需要在subscribe寫for循環
jsut可以直接傳遞事件集,但接收方接收的也是事件集,可以在接收方主動寫for循環來拿到每一個對象
fromXXX中也很多個系列,如果是集合則調用fromIterable,數組則可以調用fromArray,from可以直接傳遞事件集,接收方也會自動將集合遍歷

回到主題,假設我們現在有這樣一個需求,上游發送一個學生集合,下游需要打印出每一個學生的各個課程,每個學生都有多門課程。

發送學生對象,接收課程對象,我們首先想到的是map的轉化

 Observable.fromIterable(studentList).map(new Function<Student, List<Course>>() {
        @Override
        public List<Course> apply(Student student) throws Exception {
            Log.d("TAG",student.name);
            return student.courseList;
        }
    }).subscribe(new Consumer<List<Course>>() {
        @Override
        public void accept(List<Course> courses) throws Exception {
            for(int i=0;i<courses.size();i++){
                Log.d("TAG",courseList.get(i).name);
            }
        }
    });

輸出結果

D/TAG: 王二
D/TAG: 數據結構
D/TAG: 操作系統
D/TAG: 算法導論
D/TAG: 張三
D/TAG: 數據結構
D/TAG: 操作系統
D/TAG: 算法導論
D/TAG: 李四
D/TAG: 數據結構
D/TAG: 操作系統
D/TAG: 算法導論

這樣寫是沒有問題的,但在輸出時,多了一層for循環的嵌套,我們來試試flatMap

Observable.fromIterable(studentList).flatMap(new Function<Student, ObservableSource<Course>>() {
       @Override
       public ObservableSource<Course> apply(Student student) throws Exception {
           Log.d("TAG",student.name);
           return Observable.fromIterable(student.courseList);
       }
   }).subscribe(new Consumer<Course>() {
       @Override
       public void accept(Course course) throws Exception {
           Log.d("TAG",course.name);
       }
   });

輸出結果

D/TAG: 王二
D/TAG: 數據結構
D/TAG: 操作系統
D/TAG: 算法導論
D/TAG: 張三
D/TAG: 數據結構
D/TAG: 操作系統
D/TAG: 算法導論
D/TAG: 李四
D/TAG: 數據結構
D/TAG: 操作系統
D/TAG: 算法導論

結果分析
兩種方式都能達到我們的目的,即輸出每一個學生的多門課程。
不過顯然flatMap比map少了一層嵌套,代碼格式看著更舒服。

3. 其它

doOnNext

  • do系列的作用是side effect,當onNext發生時,它被調用,不改變數據流。
  • doOnNext()允許我們在每次輸出一個元素之前做一些額外的事情。

舉個例子

getUser(userId)
    .doOnNext(new Action1<User>() {
        @Override
        public void call(User user) {
            processUser(user);
        })
    .observeOn(AndroidSchedulers.mainThread())
    .subscribe(new Observer<User>() {
        @Override
       public void onNext(User user) {
            userView.setUser(user);
        }

        @Override
        public void onCompleted() {
        }

        @Override
        public void onError(Throwable error) {
            // Error handling
            ...
        }
    });

在使用User信息之前,在doOnNext方法里對User信息進行了處理,最后執行了subscriber里的OnNext方法。

zip

zip操作示意圖.png

簡單來講,zip可以將多個操作合并在一起
場景,有一個頁面在展示之前,需要等待兩個接口都請求完成之后,將兩個接口的數據整合在一起,然后才展示頁面

看一下zip的源碼

@SuppressWarnings("unchecked")
@CheckReturnValue
@SchedulerSupport(SchedulerSupport.NONE)
public static <T1, T2, R> Observable<R> zip(
        ObservableSource<? extends T1> source1, ObservableSource<? extends T2> source2,
        BiFunction<? super T1, ? super T2, ? extends R> zipper) {
    ObjectHelper.requireNonNull(source1, "source1 is null");
    ObjectHelper.requireNonNull(source2, "source2 is null");
    return zipArray(Functions.toFunction(zipper), false, bufferSize(), source1, source2);
}

舉個例子,我們的兩個接口分別是
Observable<Response1>和Observable<Response2>
調用zip操作可以在Response1和Response2都請求完之后,合并成Response3,即BiFunction< Response1,Response2,Response3>

關于RxJava的使用就先到這,要了解更多,請點擊文章開頭的鏈接學習,接下來我來談一談RxJava和Retrofit的混合使用

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容