1. 程式人生 > >RxJava從入門到不離不棄(三)——轉換操作符

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機動車
這裡寫圖片描述