如今的Android社群,人人都在討論RxJava以及為什麼我們應該在專案中使用RxJava。當我們開始在Android專案中使用RxJava的時候,就已經意識到了,我們的程式碼庫可以不再需要Otto了(或其他事件匯流排類庫)。
使用MVP構建程式碼庫
當我們在開發一款叫做Radyoland的無線流媒體應用的時候,我們決定使用MVP模式來設計我們的程式碼庫和專案架構等。於是我們把它分為幾個層(domain, model, app等等)。
在model層中,存在一些類和介面用來處理RESTful。而domain層中,我們試圖實現應用的業務邏輯,因此建立了一些usecase類。
為什麼需要事件匯流排類庫?
如果你的Android程式中有超過一個邏輯層,就意味著你有可能在層與層之間進行資料的傳遞。在我們的例子中,我們認為,為DataBus和UIBus建立一個BusUtil就能夠輕鬆實現層與層之間的資料傳遞(model, domain, presentation)。
你可以“訂閱”或者“取消訂閱”從bus中所傳送出的具體事件。這個方法的工作原理看起來就是這樣。
在UsecaseController,PresenterImp 類之間,我們把REST實現類中得到的結果作為事件傳送,然後訂閱此事件。
1 2 3 4 5 6 7 8 9 10 11 12 |
@Override public void getRadioList() { Call radioWrapperCall = restInterface.getRadioList(); radioWrapperCall.enqueue(new Callback() { @Override public void onResponse(Response response, Retrofit retrofit) { dataBus.post(response.body()); } @Override public void onFailure(Throwable t) { Timber.e(t.getMessage()); } }); } |
當我們通過回撥函式進行非同步請求的時候,使用bus傳送請求成功後的結果,然後訂閱這個結果事件。
1 2 3 4 |
@Subscribe @Override public void onRadioListLoaded(RadioWrapper radioWrapper) { new SaveDatabase(radioWrapper, databaseSource).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); uiBus.post(radioWrapper); } |
然後再次傳送這個事件至更新UI。Activity 或者Fragment 應該在onResume()方法中訂閱需要的事件,相反地,在onPause()中對不需要的事件解除訂閱。
1 2 3 4 |
@Subscribe @Override public void onRadioListLoaded(RadioWrapper radioWrapper) { radioListView.onListLoaded(radioWrapper); radioListView.dismissLoading(); } |
雖然,這種方案很有效。但是,作為優秀的Android工程師,應該嘗試去發現更好的實現思路。因此,我們找到了一種擺脫所有回撥函式和訂閱方法的思路。那就是在Android應用的程式碼庫中引入並使用RxJava和RxAndroid。
如何使用RxJava
首先,我們需要更改所有REST介面的返回型別。
不使用RxJava:
1 2 |
@GET("") Call getRadioList(); |
使用RxJava:
1 2 |
@GET("") Observable getRadioList(); |
在REST實現類中,我們持有很多API呼叫方法。在這裡,我只舉出其中一例。開始使用RxJava之後,我們需要修改所有方法的實現方式。返回型別將變為Observable,當做完必要的修改之後,方法看起來如下:
1 2 3 |
@RxLogObservable @Override public Observable getRadioList() { return restInterface.getRadioList(); } |
我們已經完成了REST實現類的修改。接下來,我們要做的是修改usecase實現類和其中的方法。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
@Override public Observable getRadioList() { /** * Get radiolist observable from Cache */ Observable radioListDB = databaseSource.getRadioList().filter(new Func1() { @Override public Boolean call(RadioWrapper radioWrapper) { return radioWrapper.radioList.size() > 0; } }).subscribeOn(Schedulers.computation()); /** * Load radiolist from api layer and save it to DB. */ Observable radioListApi = apiSource.getRadioList().doOnNext(new Action1() { @Override public void call(final RadioWrapper radioWrapper) { Observable.create(new Observable.OnSubscribe() { @Override public void call(Subscriber super Object> subscriber) { databaseSource.save(radioWrapper); subscriber.onCompleted(); } }).subscribeOn(Schedulers.computation()).subscribe(); } }).subscribeOn(Schedulers.io()); /** * concat db and api observables */ return Observable.concat(radioListDB, radioListApi).observeOn(AndroidSchedulers.mainThread()); } |
現在,getRadioList()
方法將返回Observable資料流傳至UI。就如你所見到的一樣,我們不再使用Event bus來傳送事件了。可以通過對資料流的過濾,合併,快取或者其他操作,來達到我們的目的了。
我們學到了什麼
儘管RxJava用起來不是那麼容易,但是當用RxJava替換掉Otto後,我們從程式碼庫中成功移除了很多回撥程式碼塊。依我看來,RxJava最棒的地方就是能夠對任何REST API進行非同步請求。