RxJava是什麼
是一個異步庫
RxJava好處是什麼
讓代碼簡潔,有序
RxJava的一些概念
- 重構的觀察者
普通的觀察者Observer
和Observable
,構成觀察者-被觀察者關係後,觀察者回調方法只有一個。
而RxJava 的觀察者增加了
- onNext 表示事件響應後,下一步操作
- onError 表示事件內部處理出錯。
- onComplete 或者成功完成觀察者的回調。
-
RxJava 的觀察者包含 Observer 和 另一個替代 Observer 的 Subscriber 。
-
RxJava 有4個新增概念:觀察者(Observer),被觀察者(Observable),事件,訂閱(subscribe)。
RxJava的基本用法
1. 首先要創建一個觀察者 Observer:
Observer<String> observer = new Observer<String>() {
@Override
public void onNext(String s) {
Log.d(tag, "Item: " + s);
}
@Override
public void onCompleted() {
Log.d(tag, "Completed!");
}
@Override
public void onError(Throwable e) {
Log.d(tag, "Error!");
}
};
RxJava提供了一個可替換的 觀察者 : Subscriber , 基本實現和Observer類似,也有些基本區別:
- onStart(): 這是 Subscriber 增加的方法。它會在 subscribe 剛開始,而事件還未發送之前被調用,可以用於做一些準備工作,例如數據的清零或重置。這是一個可選方法,默認情況下它的實現爲空。需要注意的是,如果對準備工作的線程有要求(例如彈出一個顯示進度的對話框,這必須在主線程執行), onStart() 就不適用了,因爲它總是在 subscribe 所發生的線程被調用,而不能指定線程。要在指定的線程來做準備工作,可以使用 doOnSubscribe() 方法,具體可以在後面的文中看到。
- unsubscribe(): 這是 Subscriber 所實現的另一個接口 Subscription 的方法,用於取消訂閱。在這個方法被調用後,Subscriber 將不再接收事件。一般在這個方法調用前,可以使用 isUnsubscribed() 先判斷一下狀態。 unsubscribe() 這個方法很重要,因爲在 subscribe() 之後, Observable 會持有 Subscriber 的引用,這個引用如果不能及時被釋放,將有內存泄露的風險。所以最好保持一個原則:要在不再使用的時候儘快在合適的地方(例如 onPause() onStop() 等方法中)調用 unsubscribe() 來解除引用關係,以避免內存泄露的發生。
2. 創建被觀察者
Observable observable = Observable.create(new Observable.OnSubscribe<String>() {
@Override
public void call(Subscriber<? super String> subscriber) {
subscriber.onNext("Hello");
subscriber.onNext("Hi");
subscriber.onNext("Aloha");
subscriber.onCompleted();
}
});
看到上面的Observable.OnSubscribe接口沒,就是他最終調用了 subscriber 的事件發送方法onNext(), onCompleted()等。
3. 使用subscribe方法讓二者建立訂閱關係
observable.subscribe(observer);
以上,就建立了觀察者和被觀察者之間的訂閱關係。
其實現代碼,也給一下, 後面會用到:
// 注意:這不是 subscribe() 的源碼,而是將源碼中與性能、兼容性、擴展性有關的代碼剔除後的核心代碼。
// 如果需要看源碼,可以去 RxJava 的 GitHub 倉庫下載。
public Subscription subscribe(Subscriber subscriber) {
subscriber.onStart();
onSubscribe.call(subscriber);
return subscriber;
}
除了上面的那種 Observer, 還可以給subcribe()方法傳入不完整的接口:
Action1<String> onNextAction = new Action1<String>() {
// onNext()
@Override
public void call(String s) {
Log.d(tag, s);
}
};
Action1<Throwable> onErrorAction = new Action1<Throwable>() {
// onError()
@Override
public void call(Throwable throwable) {
// Error handling
}
};
Action0 onCompletedAction = new Action0() {
// onCompleted()
@Override
public void call() {
Log.d(tag, "completed");
}
};
// 自動創建 Subscriber ,並使用 onNextAction 來定義 onNext()
observable.subscribe(onNextAction);
// 自動創建 Subscriber ,並使用 onNextAction 和 onErrorAction 來定義 onNext() 和 onError()
observable.subscribe(onNextAction, onErrorAction);
// 自動創建 Subscriber ,並使用 onNextAction、 onErrorAction 和 onCompletedAction 來定義 onNext()、 onError() 和 onCompleted()
observable.subscribe(onNextAction, onErrorAction, onCompletedAction);
上面的Action0, Action1, Action2 ,就是RxJava提供的自定義類型接口。都可以匿名內部類對象的形式,傳給observable.subscribe()
. Action0
提供一個 call()
無參無返回值的方法, Action1 的call方法會多一個參數,他們都是對 onComplete()方法的包裝,而已,最終,會回調到 call()方法。(ps:RxJava2 好像去掉這個Action0了)
4. 創建事件序列
有了觀察者,被觀察者之間的訂閱關係,還需要產生事件,在觀察者和被觀察者之間流動對吧,所以RxJava提供了
- create(“Hello”, “Hi”, “Aloha”)
- just(…)
- from(“Hello”, “Hi”, “Aloha”"")
等方法,去創造事件序列
Scheduler
一般使用RxJava時,我們這樣用:
int drawableRes = ...;
ImageView imageView = ...;
Observable.create(new OnSubscribe<Drawable>() {
@Override
public void call(Subscriber<? super Drawable> subscriber) {
Drawable drawable = getTheme().getDrawable(drawableRes));
// 產生事件的位置
subscriber.onNext(drawable);
subscriber.onCompleted();
}
})
.subscribeOn(Schedulers.io()) // 指定 subscribe() 發生在 IO 線程
.observeOn(AndroidSchedulers.mainThread()) // 指定 Subscriber 的回調發生在主線程
.subscribe(new Observer<Drawable>() {
@Override
public void onNext(Drawable drawable) {
// 消耗事件的位置
imageView.setImageDrawable(drawable);
}
@Override
public void onCompleted() {
}
@Override
public void onError(Throwable e) {
Toast.makeText(activity, "Error!", Toast.LENGTH_SHORT).show();
}
});
上面,通過調用 subscribeOn(Schedulers.io())
, .observeOn(AndroidSchedulers.mainThread())
, 我們可以指定執行產生事件的線程Schedulers.io(), 消耗事件回調方法所在的線程AndroidSchedulers.mainThread(),那RxJava是如何做到的呢?
首先,我們要理解它的一個方法(或者叫概念,又是概念)
變換事件
RxJava內部,通過一個稍顯複雜的操作,可以“將事件序列中的對象或整個序列進行加工處理,轉換成不同的事件或事件序列“,
事件序列是啥?先來一段代碼:
Observable.just("images/logo.png") // 輸入類型 String
.map(new Func1<String, Bitmap>() {
@Override
public Bitmap call(String filePath) { // 參數類型 String
// 位置1
return getBitmapFromPath(filePath); // 返回類型 Bitmap
}
})
.subscribe(new Action1<Bitmap>() {
@Override
public void call(Bitmap bitmap) { // 參數類型 Bitmap
// 位置2
showBitmap(bitmap);
}
});
上面的 new Func1(), 還有 new Aciton1() 匿名類對象,都是 事件,他們會有一些事件方法,方法的參數,看着不同啊,那,代碼爲何可以從一個方法跳到另一個方法**(位置1 -》 位置2)**執行呢?
原因就是有 map() 這個方法。他可以將一個事件或者事件序列變換成另一個事件或者事件序列。
具體的原理呢,後續會講到(也可能講不到)。~~!
總之,這個map()方法非常重要,也非常牛逼,先記住:map()做到了事件或者事件序列的轉換。
當然, 還有其他方法,map方法更牛逼:
- flatMap() 非常6的一個方法,解釋起來都困難(暫時不解釋了),
和map的區別是:變換後返回值是一個Observable對象。
- throttleFirst() 每次事件觸發後的一定時間間隔內丟棄新的事件。常用作去抖動過濾,例如按鈕的點擊監聽器:
變換的原理
這一段最繞了。不過還是可以看一看。
- 變換雖然功能各有不同,但實質上都是針對事件序列的處理和再發送。而在 RxJava 的內部,它們是基於同一個基礎的變換方法: lift(Operator)。
代碼1
// 注意:這不是 lift() 的源碼,而是將源碼中與性能、兼容性、擴展性有關的代碼剔除後的核心代碼。
// 如果需要看源碼,可以去 RxJava 的 GitHub 倉庫下載。
public <R> Observable<R> lift(Operator<? extends R, ? super T> operator) {
return Observable.create(new OnSubscribe<R>() {
@Override
public void call(Subscriber subscriber) {
Subscriber newSubscriber = operator.call(subscriber);
newSubscriber.onStart();
onSubscribe.call(newSubscriber);
}
});
}
上面一段代碼發生了神馬?爲什麼就可以執行變換事件或者事件序列的牛皮操作呢?
這裏,我把之前 subscribe()方法也拷過來,對比一下:
代碼2
// 注意:這不是 subscribe() 的源碼,而是將源碼中與性能、兼容性、擴展性有關的代碼剔除後的核心代碼。
// 如果需要看源碼,可以去 RxJava 的 GitHub 倉庫下載。
public Subscription subscribe(Subscriber subscriber) {
subscriber.onStart();
onSubscribe.call(subscriber);
return subscriber;
}
這裏,代碼1那段call()
方法幾乎和代碼2的 subscribe()
方法類似 ,新生成了一個 newSubscriber
(前面說過,等價於 Observer
), 然後調用 onStart()
方法,把 newSubscriber
關聯到舊的 onSubscribe 對象中。
- subscribe() 中這句話的 onSubscribe 指的是 Observable 中的 onSubscribe 對象,是否還記得create 方法?
- 當含有 lift() 時:
-
lift() 創建了一個 Observable 後,加上之前的原始 Observable,已經有兩個 Observable 了;
-
而同樣地,新 Observable 裏的新 OnSubscribe 加上之前的原始 Observable 中的原始 OnSubscribe,也就有了兩個 OnSubscribe;
-
當用戶調用經過 lift() 後的 Observable 的 subscribe() 的時候,使用的是 lift() 所返回的新的 Observable ,於是它所觸發的 onSubscribe.call(subscriber),也是用的新 Observable 中的新 OnSubscribe,即在 lift() 中生成的那個 OnSubscribe;
-
而這個新 OnSubscribe 的 call() 方法中的 onSubscribe ,就是指的原始 Observable 中的原始 OnSubscribe ,在這個 call()方法裏,新 OnSubscribe 利用
operator.call(subscriber)
生成了一個新的Subscriber
(Operator 就是在這裏,通過自己的call()
方法將新 Subscriber 和原始 Subscriber 進行關聯,並插入自己的『變換』代碼以實現變換),然後利用這個新 Subscriber 向原始 Observable 進行訂閱。
這樣就實現了 lift() 過程,有點像一種代理機制,通過事件攔截和處理實現事件序列的變換。
-
第4點太繞了。
用自己的話描述,就是: Observable 執行了lift操作,形成一個新的Observable對象,代理了舊的Observable,有事件過來,先通過新的,轉發給舊的,舊的再通知代理的 Subscriber
. 最後再分發給 目標 Subscriber
。
還是打個比方吧:
有個賣房子的中介毛利小O
, 現在有個人Subscriber
要找他買房子,但是他沒有房源;
於是,他只能找售樓部的中介 工藤新O
, 中介 毛利小O
的買房人就成爲工藤新O
的 Subscriber
。but!中介 工藤新O
很聰明,他要搞個操作對毛利小O
的買房人(舊的Subscriber)進行一層關聯和變換。即:operator.call(subscriber)
。生成一個新的Subscriber, 並且裏面有自己的一些操作。然後調用onSubscribe.call(newSubscriber) 把新的和舊的進行一個關聯。
接着,中介 工藤新O
就能利用新的Subscriber,實現自己的目的了(對房價實現一些不可告人的操作)了。
線程控制的原理
to be continue