淺談 RxAndroid + Retrofit + Databinding

znwo0278 8年前發布 | 103K 次閱讀 Android開發 移動開發

來自: http://www.jcodecraeer.com//a/anzhuokaifa/androidkaifa/2016/0131/3930.html



淺談 RxAndroid + Retrofit + Databinding


最近 RxAndroid 、MVP、MVVM 一直是 Android 程序猿茶余飯后的談資,于是我也抱著湊熱鬧的態度試試了試水。這里就談談試水后的感受

什么是 RxAndroid ?

要說什么是 RxAndroid ,得從 RxJava 說起。RxJava 在 GitHub 主頁上的自我介紹是 “a library for composing asynchronous and event-based programs using observable sequences for the Java VM”(一個在 Java VM 上使用可觀測的序列來組成異步的、基于事件的程序的庫)。這就是 RxJava ,概括得非常精準。

RxJava 的本質可以壓縮為異步這一個詞。說到根上,它就是一個實現異步操作的庫,而別的定語都是基于這之上的。

而RxAndroid是RxJava的一個針對Android平臺的擴展,主要用于 Android 開發。

什么是 Retrofit ?

Retrofit 是一套 RESTful 架構的 Android(Java) 客戶端實現,基于注解,提供 JSON to POJO(Plain Ordinary Java Object ,簡單 Java 對象),POJO to JSON,網絡請求(POST,GET, PUT,DELETE 等)封裝。

既然只是一個網絡請求封裝庫,現在已經有了那么多的大家已經耳熟能詳的網絡請求封裝庫了,為什么還要介紹它呢,原因在于 Retrofit 是一套注解形的網絡請求封裝庫,讓我們的代碼結構更給為清晰。它可以直接解析JSON數據變成JAVA對象,甚至支持回調操作,處理不同的結果。主要是 Retrofit 能很好的與 RxAndroid 配合使用。

想更詳細的了解 Retrofit,可以查看官方文檔

什么是 MVVP ?

MVC(Model-View-Controller)和 MVP(Model-View-Presenter)是最常見的軟件架構之一,業界有著廣泛應用,大家一定不陌生。但知道什么事 MVVP 的就不多了,它本身很容易理解,但是要講清楚,這幾個架構的區別就不容易了。

MVVM(Model-View-ViewModel),它采用雙向綁定(data-binding):View的變動,自動反映在 ViewModel,反之亦然。Angular 和 Ember 都采用這種模式。

而 Google 新推出的 Databinding 正是采用了這種模式。

RxAndroid + Retrofit + Databinding

上面已經分別介紹了 RxAndroid、Retrofit、Databinding ,想必大家也有了個初步的認識,那我們就看看 RxAndroid + Retrofit + Databinding 產生的“化學反應”。

private void initActionBar() {
    setSupportActionBar(getBinding().toolbar);

    DrawerLayout drawer = getBinding().drawLayout;     ActionBarDrawerToggle toggle = new ActionBarDrawerToggle(this, drawer, getBinding().toolbar, R.string.navigation_drawer_open, R.string.navigation_drawer_close);     drawer.setDrawerListener(toggle);     toggle.syncState();

    getBinding().navigationView.setNavigationItemSelectedListener(this); }</pre>

代碼中不再充斥著 findViewById 這樣的代碼了,將 etContentView() 換成下面的方法。

this.mBinding = DataBindingUtil.setContentView(context, layout_id);

系統會將我們的 layout 和 data 進行綁定并返回 bind 對象,bind.* 或者 bind.set 方法來取得控件或修改值。當然還有其它的方法,但是你此時再使用 findViewById() 方法不再有效了。

public interface NewsApi {   
    /*
      根據 ID 請求新聞列表
      @param id
      @return
     */    
     @Headers("apikey: 2c61a1cd1f64216e92f7da1603697bf7")    
     @GET(ApiConst.NEWS) Observable<News.NewsData> queryNewsByID(@Query("channelId") String id, @Query("page") int page);  

    /*       根據 ChannelName (標題)請求新聞列表       @param title       @return      */          @Headers("apikey: 2c61a1cd1f64216e92f7da1603697bf7")          @GET(ApiConst.NEWS) Observable<News.NewsData> queryNewsByCName(@Query("channelName") String title, @Query("page") int page);    

     /*       根據 title (標題)請求新聞列表       @param title       @return      */          @Headers("apikey: 2c61a1cd1f64216e92f7da1603697bf7")          @GET(ApiConst.NEWS) Observable<News.NewsData> queryNewsByTitle(@Query("title") String title, @Query("page") int page);

}</pre>

private void initObservables() {
    Observable.Transformer<List<News>, List<News>> networkingIndicator = RxNetworking.bindRefreshing(getBinding().refresher);

    observableRefresherNewsData = Observable.defer(() -> mNewApi.queryNewsByCName(getArguments().getString(BUNDLE_NAME), 1))             .doOnUnsubscribe(() -> this.unsubcribe("observableNewsData"))             .flatMap(data -> Observable.just(data.contentlist))             .flatMap(list -> getApp().getDB().putList(Const.DB_NEWS_NAME, list, News.class))             .subscribeOn(Schedulers.io())             .observeOn(AndroidSchedulers.mainThread())             .compose(networkingIndicator);    

    observableLoadMoreNewsData = Observable.defer(() -> mNewApi.queryNewsByCName(getArguments().getString(BUNDLE_NAME), mCurrPage + 1))             .doOnUnsubscribe(() -> this.unsubcribe("observableNewsData"))             .map(data -> {                 mCurrPage = data.currentPage;                                return data.contentlist;             })             .subscribeOn(Schedulers.io())             .observeOn(AndroidSchedulers.mainThread())             .compose(networkingIndicator);

    // 刷新/加載更多         RxSwipeRefreshLayout.refreshes(getBinding().refresher)             .doOnUnsubscribe(() -> this.unsubcribe("SwipeRefreshLayout"))             .flatMap(avoid -> observableRefresherNewsData)             .compose(bindToLifecycle())             .subscribe(RxList.prependTo(mNews, getBinding().content), this::showError);         RxEndlessRecyclerView.reachesEnd(getBinding().content)             .doOnUnsubscribe(() -> this.unsubcribe("Recycler"))             .flatMap(avoid -> observableLoadMoreNewsData)             .compose(bindToLifecycle())             .subscribe(RxList.appendTo(mNews), this::showError);

    // 首次進入手動加載         observableRefresherNewsData             .map(list -> {                 mNews.clear();                                return list;             })             .compose(bindToLifecycle())             .subscribe(RxList.prependTo(mNews, getBinding().content), this::showError);

}</pre>

上面代碼是使用 Retrofit 以 Get 形式從服務器中獲取對應的新聞數據,大家可以看到代碼的邏輯非常清晰,代碼也很簡潔(這里使用了 lambda 表達式,不使用的話,代碼會長些,但是邏輯依然清晰),如果是按以前的寫法的話,我們的代碼會比這復雜的多,還涉及到復雜的線程之間的通信。而通過 RxJava ,我們只需要簡單的使用 subscribeOn(Schedulers.io()) 和 observeOn(AndroidSchedulers.mainThread()) 就可以完成 IO 線程和 UI 線程的切換。

帥的簡直不敢相信,原來還可以這樣玩。

總結

優點:

  1. 代碼邏輯更多加清晰。

  2. 線程之間的切換更加方便、自如。

  3. 代碼可擴展性高,便于維護。

  4. 不再為 findViewById() 方法而煩,為 Activity 減負,整體結構更加清晰。

缺點:

  1. 代碼出錯時,由于 RxJava 的原因,將不太容易找到具體出錯位置。

  2. 由于 RxJava 結構問題,部分需要捕捉的錯誤可能被 RxJava 消化掉。

  3. Databinding 在部分情況使用不太如意,如 include 進來的 layout 里對應的 id 不會被關聯起來。

  4. 需要一定的學習成本(當然這不是問題)。

廣告

這里打個小廣告,介紹下我最近開發的幾個小應用

小白球

私人訂制

輕截

大家多支持下,如果下載達到 1000 的話,我會將其中一兩個項目開源出來的哦。

擴展閱讀

  1. RxJava / RxAndroid

  2. Retrofit:

  3. Databinding

 本文由用戶 znwo0278 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!