天天看點

RxJava學習筆記3

RxJava學習筆記2介紹了在RxJava中如何指定事件發生線程以及事件消費線程,隻需要簡單調用

subscribeOn(XXXX) //發生線程
observeOn(XXX) //指定消費線程
           

這一篇我來學習一下RxJava中的核心原理 >>>>變換

就是将事件序列中的對象或整個序列進行加工處理,轉換成不同的事件或事件序列

->看不懂沒關系 我看都不看!!!!!

map( ) 和 flatMap( ) 變換

/********   map()變換  ********/
Observable.just("images/logo.png") // 輸入類型 String
    .map(new Func1<String, Bitmap>() {
        public Bitmap call(String filePath) { // 參數類型 String
            return getBitmapFromPath(filePath); // 傳回類型 Bitmap
        }
    })
    .subscribe(new Action1<Bitmap>() {
        public void call(Bitmap bitmap) { // 參數類型 Bitmap
            showBitmap(bitmap);
        }
    });
//這個看起來很好了解吧  傳入一個String類型的圖檔位址,在消費事件中拿到的是一個Bitmap圖檔
//Func1 -> 和我們之前寫的非完整定義的Action0,1,2一樣

/**  new  Func1(T1 , T2)  第一個參數是表示傳入參數的資料類型 第二個參數 是傳回結果的參數資料類型***/

//FuncX 和 ActionX 的差別在 FuncX 包裝的是有傳回值的方法。
           

以上的變化可以說是很好了解,下面再來看一個場景:

//假設有一個資料結構學生,現在需要列印出一組學生的名字。實作方式很簡單:
Student[] students = ...;
Subscriber<String> subscriber = new Subscriber<String>() {
    public void onNext(String name) {
        Log.d(tag, name);
    }
};
Observable.from(students)
    .map(new Func1<Student, String>() {
        public String call(Student student) {
            return student.getName();
        }
    })
    .subscribe(subscriber);
    //map就是這麼好用,如果要我們去列印學生選的課程,注意 課程也不是一個簡單的資料哦,也是一個比較複合的資料接口,我們聰明的讀者肯定想到了把我們傳遞的名字換成課程這個結構,在消費事件裡面去一一解析即可,對,完全可以,但是我們為了體驗一下FlatMap(),我們強制規定隻能傳入一個個解析好的課程名字給消費線程,我一句話列印就行,這樣以來Map肯定不好使,因為Map是針對于 1  -> 1  ,但是 我們要的是 1 ->n(n>1)
 我們直接看下一段代碼
           
Student[] students = ...;
Subscriber<Course> subscriber = new Subscriber<Course>() {
    public void onNext(Course course) {
        Log.d(tag, course.getName());
    }
};
Observable.from(students)
    .flatMap(new Func1<Student, Observable<Course>>() { //傳入一個Student >>傳回一個被觀察者 Course 
        public Observable<Course> call(Student student) {
            return Observable.from(student.getCourses()); 
        }
    })
    .subscribe(subscriber);
 //我們發現 本來是我麼建立一個Obserable 但是在内部  又建立了一個新的Obserable傳回出來  嵌套 >>


//1. 使用傳入的事件對象建立一個 Observable 對象; 
//就是我們最原始的資料  攜帶 Student資訊的Observable 

//2. 并不發送這個 Observable, 而是将它激活,于是它開始發送事件;
//利用 每一個 Student擷取到的相應的課程資訊 Course而建立的Obserable 
//-> 第一級的Obserable發送 事件 就是 每次都發送一個Student給 第二級 事件 處理 第一級的發送事件  是拿到解析出來的相應Course 一個個發送給列印訂閱者


//3. 每一個建立出來的 Observable 發送的事件,都被彙入同一個 Observable ,

//而這個 Observable 負責将這些事件統一交給 Subscriber 的回調方法。
//這三個步驟,把事件拆成了兩級,通過一組新建立的 Observable 将初始的對象鋪平之後通過同一天鍊分發了下去。而這個鋪平就是flatMap()的完成的操作。


//其實這很好了解 >>> 流水線型 
類似于 組裝的逆向過程  一輛車 >>>拆下車輪 >>>各種單體材料 
肯定是在一個流水線上的  >>>車 >>>個輪子 >>>一個輪子 好多螺絲 (好像有點牽強,但是就是這個理)
           

RxJava的所有變換其實都是利用 lift(Operator )來完成的

// lift()核心代碼。
public <R> Observable<R> lift(Operator<? extends R, ? super T> operator) {
    return Observable.create(new OnSubscribe<R>() {
        public void call(Subscriber subscriber) {
            Subscriber newSubscriber = operator.call(subscriber);
            newSubscriber.onStart();
            onSubscribe.call(newSubscriber);
        }
    });
}

//在 Observable 執行了 lift(Operator) 方法之後,會傳回一個新的 Observable,

//這個新的 Observable 會像一個代理一樣,負責接收原始的 Observable 發出的事件,并在處理後發送給 Subscriber。

//類似一種代理機制,通過事件攔截和處理實作事件序列的變換。

![這裡寫圖檔描述](http://img.blog.csdn.net/20160316113248554)
           

lift的使用示例

//下面這是一個将事件中的 Integer 對象轉換成 String 的例子,僅供參考:
observable.lift(new Observable.Operator<String, Integer>() {
    public Subscriber<? super Integer> call(final Subscriber<? super String> subscriber) {
        // 将事件序列中的 Integer 對象轉換為 String 對象
        return new Subscriber<Integer>() {
            public void onNext(Integer integer) {
                subscriber.onNext("" + integer);
            }
            public void onCompleted() {
                subscriber.onCompleted();
            }
            public void onError(Throwable e) {
                subscriber.onError(e);
            }
        };
    }
});


//**然而不管你是否了解了 lift() 的原理,RxJava 都不建議開發者自定義 Operator 來直接使用 lift(),而是建議盡量使用已有的 lift() 包裝方法(如 map() flatMap() 等)進行組合來實作需求,因為直接使用 lift() 非常容易發生一些難以發現的錯誤。**
           

compose: 對 Observable 整體的變換 RxJava的另一個變換

lift() 是針對事件項和事件序列的,而 compose() 是針對 Observable 自身進行變換

假設在程式中有多個 Observable ,并且他們都需要應用一組相同的 lift() 變換。你可以這麼寫:

observable1
    .lift1()
    .lift2()
    .lift3()
    .subscribe(subscriber1);
observable2
    .lift1()
    .lift2()
    .lift3()
    .subscribe(subscriber2);
observable3
    .lift1()
    .lift2()
    .lift3()
    .subscribe(subscriber3);
           

更新一下>>>>>>

private Observable liftAll(Observable observable) {
    return observable
        .lift1()
        .lift2()
        .lift3()
}
liftAll(observable1).subscribe(subscriber1);
liftAll(observable2).subscribe(subscriber2);
liftAll(observable3).subscribe(subscriber3);
//可是 Observable 被一個方法包起來,這種方式對于 Observale 的靈活性似乎還是增添了那麼點限制。怎麼辦?這個時候,就應該用 compose() 來解決了:
           
public class LiftAllTransformer implements Observable.Transformer<Integer, String> {
    @Override
    public Observable<String> call(Observable<Integer> observable) {
        return observable
            .lift1()
            .lift2()
            .lift3()
    }
}
Transformer liftAll = new LiftAllTransformer();
observable1.compose(liftAll).subscribe(subscriber1);
observable2.compose(liftAll).subscribe(subscriber2);
observable3.compose(liftAll).subscribe(subscriber3);
//使用 compose() 方法,Observable 可以利用傳入的 Transformer 對象的 call 方法直接對自身進行處理,也就不必被包在方法的裡面了。