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。
//類似一種代理機制,通過事件攔截和處理實作事件序列的變換。

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 方法直接對自身進行處理,也就不必被包在方法的裡面了。