都說RxJava 是非常強(qiáng)大但是難于上手的完箩。我接觸RxJava已經(jīng)有一段時(shí)間了,今天就從自己的項(xiàng)目中拉队,將用到RXJava的部分單獨(dú)的拿出來寫一篇文章弊知,用來幫助看了很多RxJava相關(guān)的文章但是還不知道怎么去使用的同學(xué)。
前言
閱讀本文章之前粱快,我們在回顧或者加強(qiáng)幾個(gè)基本概念秩彤。
Observer:觀察者
Observable:可觀察者
Subscribe:訂閱
observalbe(觀察者) subscribe(訂閱) observer(被觀察者)
Tips
上面的邏輯看起來和我們正常的邏輯是相反的夺鲜,按照常理來說不應(yīng)該是被觀察者訂閱觀察者嗎?為什么反過來了呐舔,具體原因可以在 給Android開發(fā)者的 RxJava 詳解 中找到答案
RxJava使用三步走
RxJava基本實(shí)現(xiàn)只需要三步
- 創(chuàng)建Observer
- 創(chuàng)建Observable
- 訂閱
1.創(chuàng)建Observer
Observer即觀察者,他決定事件觸發(fā)的時(shí)候?qū)?huì)有什么樣的行為慷蠕∩浩矗基本的Observer我們可以這么實(shí)現(xiàn):
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!");
}
};
2.創(chuàng)建Observable
Observable 即被觀察者,他決定什么時(shí)候觸發(fā)怎樣的事件流炕。
我們可以使用create()
方法創(chuàng)建一個(gè)Observable
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();
}
});
更簡單的澎现,我們可以使用just(T...)
創(chuàng)建一個(gè)Observable
Observable observable = Observable.just("Hello", "Hi", "Aloha");
// 將會(huì)依次調(diào)用:
// onNext("Hello");
// onNext("Hi");
// onNext("Aloha");
// onCompleted();
也可以使用from(T[])
來創(chuàng)建一個(gè)Observable
String[] words = {"Hello", "Hi", "Aloha"};
Observable observable = Observable.from(words);
3.訂閱
我們創(chuàng)建了Observable
和Observer
之后,在用subscribe()
將他們鏈接起來每辟,代碼就可以工作啦剑辫。
observable.subscribe(observer);
在我自己的項(xiàng)目中RxJava使用場景舉例
RxJava與Retrofit結(jié)合
這里比較簡單,只需要稍微改變Retrofit請求接口方法的返回值類型就好了渠欺。
@GET("openapi.do?keyfrom=xxx&key=xxx&type=data&doctype=json&version=1.1")
Observable<YouDaoResult> getTranslationYouDao(@Query("q") String q);
接著使用Retrofit對象妹蔽,創(chuàng)建接口實(shí)例,調(diào)用接口方法挠将,即可獲取Observable胳岂。
我在項(xiàng)目中使用的Dagger2迫皱,所以看起來和只使用了RxJava與Retrofit的代碼有所不同
@Provides
@Singleton
public static ClientApi provideClientApi() {
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(BASE_URL)
.addCallAdapterFactory(RxJavaCallAdapterFactory.create())
.addConverterFactory(GsonConverterFactory.create())
.build();
return retrofit.create(ClientApi.class);
}
public Observable<YouDaoResult> getTranslation(String query) {
return getApi().getTranslationYouDao(query);
}
在我的項(xiàng)目中渠牲,從網(wǎng)絡(luò)獲取的實(shí)體類型是YouDaoResult,本地?cái)?shù)據(jù)庫存儲(chǔ)的實(shí)體類型是經(jīng)過簡化的Result霎桅,在業(yè)務(wù)邏輯中我想實(shí)現(xiàn)在查詢一個(gè)單詞的時(shí)候内贮,如果本地?cái)?shù)據(jù)庫已經(jīng)存在了單詞記錄就從本地讀取記錄产园,而不從網(wǎng)絡(luò)獲取。然而兩個(gè)實(shí)體類型不同夜郁,我又想使用優(yōu)雅的方法解決它什燕,我能不能獲取了YouDaoResult之后,立刻就轉(zhuǎn)換成Result呢拂酣?后來我使用了RxJava的map()
變換對象流方法秋冰。
Tips
在我的項(xiàng)目中,所有的Observable都是放在一起管理的婶熬,作為DataLayer(數(shù)據(jù)層)剑勾,在業(yè)務(wù)方法中,想要獲取數(shù)據(jù)首先要在數(shù)據(jù)層中獲取Observable赵颅,再使用RxJava的方法去處理它虽另。
@Override
public Observable<Result> getTranslation(String query) {
return getApi().getTranslationYouDao(query)
.map(new Func1<YouDaoResult, Result>() {
@Override
public Result call(YouDaoResult youDaoResult) {
return youDaoResult.getResult();
}
});
}
在這里要放大招啦,項(xiàng)目中獲取單詞的方法是怎么實(shí)現(xiàn)的饺谬。根據(jù)代碼注釋可以很直觀的看出RxJava的優(yōu)點(diǎn)捂刺,異步谣拣,簡潔,即使邏輯復(fù)雜族展,已然可以保持簡潔森缠。在查詢單詞的業(yè)務(wù)邏輯中,主要做了下面幾件事:
- 在本地?cái)?shù)據(jù)庫有單詞數(shù)據(jù)時(shí)優(yōu)先從本地?cái)?shù)據(jù)庫查詢單詞
- 本地?cái)?shù)據(jù)庫沒有單詞數(shù)據(jù)則從網(wǎng)絡(luò)獲取數(shù)據(jù)
- 單詞在輸出前進(jìn)行緩存仪缸,這里又分為兩步不過實(shí)現(xiàn)方法在數(shù)據(jù)庫層贵涵。
- 異步
public void fetchTranslation(String query) {
// 分發(fā)開始刷新列表事件(Flux架構(gòu))
getDispatcher().dispatch(new Action.Builder().with(TranslateActions.ACTION_TRANSLATION_LOADING).build());
// 本地?cái)?shù)據(jù)庫數(shù)據(jù)源
Observable<Result> cache = getDataLayer().getTranslateService().getLocalTranslation(query);
// 服務(wù)端數(shù)據(jù)源
Observable<Result> network = getDataLayer().getTranslateService().getTranslation(query);
// 沒有本地?cái)?shù)據(jù)在使用網(wǎng)絡(luò)數(shù)據(jù)
Observable<Result> source = Observable
.concat(cache, network)
// 依次遍歷序列中的數(shù)據(jù)源, 返回第一個(gè)符合條件的數(shù)據(jù)源
.first(new Func1<Result, Boolean>() {
@Override
public Boolean call(Result result) {
return result != null;
}
});
// 重新查詢數(shù)據(jù)則更新history列表恰画,在save方法中有判斷宾茂,具體見TranslateDB
source = source.doOnNext(new Action1<Result>() {
@Override
public void call(Result result) {
getDataLayer().getTranslateService().saveToHistory(result);
}
});
source.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Action1<Result>() {
@Override
public void call(Result result) {
// Flux架構(gòu)分發(fā)事件
getDispatcher().dispatch(new Action.Builder()
.with(TranslateActions.ACTION_TRANSLATION_FINISH)
.bundle(TranslateActions.KEY_TRANSLATION_ANSWER, result)
.build());
}
}, new Action1<Throwable>() {
@Override
public void call(Throwable throwable) {
// Flux架構(gòu)分發(fā)事件
Action action = new Action.Builder()
.with(TranslateActions.ACTION_TRANSLATION_NET_ERROR)
.build();
dispatcher.dispatch(action);
}
});
}
小結(jié)
RxJava并沒有那么難,我們不敢將它引入到實(shí)際開發(fā)環(huán)境的最終原因只是我們對RxJava沒有那么熟悉拴还。Talk is cheap跨晴,趕緊去練習(xí)吧。
最后放上我的項(xiàng)目地址: Translate
歡迎圍觀片林,歡迎批評端盆,歡迎討論。
延伸閱讀
中文學(xué)習(xí)資料:
給 Android 開發(fā)者的 RxJava 詳解
過濾序列 | RxJava Essentials CN
lzyzsd/Awesome-RxJava: RxJava resources
RxJava 與 Retrofit 結(jié)合的最佳實(shí)踐