Android RxJava系列一: 基礎常用詳解

前言

本篇主要介紹RxjavaAndroid 項目中的基礎使用和常用方法,旨在給對 RxJava 感興趣的人一些入門的指引.對Rxjava不熟悉的朋友可以去看我之前寫的一篇簡單介紹 Android RxJava:基礎介紹與使用 ,下面就來我們一起來看看在項目中如何使用 Rxjava 吧!

Rxjava是什么?為什么要用Rxjava?

首先我們要知道Rxjava到底是什么東西?為什么這么多人用它以及它在Android項目中所占的比重.

  • Rxjava到底是什么呢?

RxJava 在 GitHub 主頁上的自我介紹是 : a library for composing asynchronous and event-based programs using observable sequences for the Java VM (一個在 Java VM 上使用可觀測的序列來組成異步的、基于事件的程序的庫)。這就是 RxJava ,概括得非常精準。然而對于初學者來說,兩個字,不懂.其實說白了,Rxjava就是一個用來實現異步操作的第三方庫,而至于其他的拓展功能也只是在實現異步過程中提供了一些輔助功能罷了.所以總結一下就一句話:

Rxjava是一個用來實現異步的、基于事件的第三方庫(就把它理解成Android Handler 的升級版就行了)

  • 為什么要用Rxjava?

這就到我們今天的重頭戲了.相信很多初學者都是在以下場景初識Rxjava的

1.201x年你必須知道的幾個Android開源庫: .......、Rxjava
這是一個基于 Rxjava+Retrofit+mvp+........的demo
Android 工作必回 Rxjava+Retrofit+.......幾件套

起初本人也是因為看到這些字眼才接觸的Rxjava的,也是因為這些原因我才使用的Rxjava. But,當你真正的去了解了Rxjava,真正的把Rxjava用到了你的項目中,你才真正知道,為啥這么多人說要用Rxjava,以及你為什么要用Rxjava ,因為Rxjava真的太好用太便捷了,用了一次你就離不開它了.

舉個例子你就能明白了:

假如現在有這么一個需求:你需要從數據庫中取出一組圖片資源id,然后通過遍歷將它們顯示在imageView上面,實現方式有很多種

  • 使用傳統方式實現
//操作數據庫屬于耗時操作,需要開辟一個新線程放在后臺操作
        new Thread() {
            @Override
            public void run() {
                super.run();
                final int[] drawableRes = {}; //.......從數據庫中取出id資源數組操作
                //將id對應 drawable顯示在界面上,需要在UI線程操作
                imageView.post(new Runnable() {
                    @Override
                    public void run() {
                        imageView.setImageResource(drawableRes[0]);
                    }
                });
            }
        }.start();
Handler handler = new Handler(){
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            //.....操作UI
            imageView.setImageResource(drawableRes[0]);
        }
    };

 new Thread(){
            @Override
            public void run() {
                super.run();
                final int[] drawableRes = {}; //.......從數據庫中取出id資源數組操作
                //將id對應 drawable顯示在界面上,需要在UI線程操作
                handler.sendEmptyMessage(0);//發送消息,通知主線程刷新UI

            }
        }.start();
  • 使用Rxjava方式實現
Observable.create(new ObservableOnSubscribe<List>() {
            @Override
            public void subscribe(ObservableEmitter<List> emitter) throws Exception {
               drawableRes = new ArrayList<>(); //.......從數據庫中取出id資源數組操作
               emitter.onNext(drawableRes);
               emitter.onComplete();
            }
        }).flatMap(new Function<List, ObservableSource<Integer>>() {
            @Override
            public ObservableSource<Integer> apply(List list) throws Exception {
                return Observable.fromIterable(list);
            }
        }).subscribeOn(Schedulers.io())//在IO線程執行數據庫處理操作
          .observeOn(AndroidSchedulers.mainThread())//在UI線程顯示圖片
          .subscribe(new Observer<Integer>() {
              @Override
              public void onSubscribe(Disposable d) {
                  Log.d("----","onSubscribe");
              }

              @Override
              public void onNext(Integer integer) {
                  imageView.setImageResource(integer);//拿到id,加載圖片
                  Log.d("----",integer+"");
              }

              @Override
              public void onError(Throwable e) {
                  Log.d("----",e.toString());
              }

              @Override
              public void onComplete() {
                  Log.d("----","onComplete");
              }
          });

誒,等一下,你不是說使用Rxjava實現代碼會更簡潔快捷嘛,我怎么看著實現還變復雜了,明明只要切換一下線程,你這咋寫了這么多,看不懂?????

咳咳,看不懂了吧,看不懂就對了,看著的確是變復雜了,But 代碼這一連串鏈式調用下來不是顯得代碼邏輯很清晰嗎.而且隨著業務需求的增多,你可能需要拿到圖片id時還要加一層過濾呢,只需要在加一個.xxx()方法即可,而且還可以隨意切換操作線程,代碼依然還是這么清晰簡潔.而且使用Android studio 打開時還會自動縮進和顯示提示信息:

Android RxJava系列一: 基礎常用詳解

上面的例子省去了部分代碼,也是我隨手寫的,只要是讓你體會一下Rxjava的書寫方式和對比一下傳統方式的實現有什么不同,看不懂沒關系,下面我會一一解釋,搬好小板凳

總結一下:

為什么要用Rxjava: 因為隨著程序邏輯變得越來越復雜,它依然能夠保持代碼的簡潔和閱讀性.

怎么用Rxjava?

關于Rxjava的簡單集成和基礎使用請查看我之前的介紹 Android RxJava:基礎介紹與使用

首先大概說一下Rxjava的原理:

1.概念: 觀察者模式

RxJava 的異步實現,是通過一種擴展的觀察者模式來實現的。 至于觀察者模式的原理實現大家肯定都已經很熟悉了,我就不再闡述了,不熟悉的可以自行搜索.

RxJava 有四個基本概念:Observable (可觀察者,即被觀察者)、 Observer (觀察者)、 subscribe (訂閱)、事件。Observable 和 Observer 通過 subscribe() 方法實現訂閱關系,從而 Observable 可以在需要的時候發出事件來通知 Observer。

RxJava 的事件回調方法除了普通事件 onNext() (相當于 onClick() / onEvent())之外,還定義了兩個特殊的事件:onCompleted() 和 onError()。

  • onCompleted(): 事件隊列完結。RxJava 不僅把每個事件單獨處理,還會把它們看做一個隊列。RxJava 規定,當不會再有新的 onNext() 發出時,需要觸發

    • onCompleted() 方法作為標志。
  • onError(): 事件隊列異常。在事件處理過程中出異常時,onError() 會被觸發,同時隊列自動終止,不允許再有事件發出。
  • 在一個正確運行的事件序列中, onCompleted() 和 onError() 有且只有一個,并且是事件序列中的最后一個。需要注意的是,onCompleted() 和 onError() 二者也是互斥的,即在隊列中調用了其中一個,就不應該再調用另一個。

Android RxJava系列一: 基礎常用詳解

  1. 基本實現
  • 創建 Observer 觀察者
Observer observer = new Observer<String>(){

            @Override
            public void onSubscribe(Disposable d) {
                Log.d("----","onSubscribe" );
            }

            @Override
            public void onNext(String s) {
                Log.d("----", s);
            }

            @Override
            public void onError(Throwable e) {
                Log.d("----", "onError");
            }

            @Override
            public void onComplete() {
                Log.d("----", "onComplete");
            }
        };
  • 創建 Observable 被觀察者
Observable observable =Observable.create(new ObservableOnSubscribe<String>() {
            @Override
            public void subscribe(ObservableEmitter<String> emitter) throws Exception {
                    emitter.onNext("rxjava");
                    emitter.onComplete();
            }
        });
  • Subscribe (訂閱)
observable.subscribe(observer);

以上就是傳統的使用方式,你也可以采用鏈式調用:

Observable.create(new ObservableOnSubscribe<String>() {
            @Override
            public void subscribe(ObservableEmitter<String> emitter) throws Exception {
                emitter.onNext("rxjava");
                emitter.onComplete();
            }
        }).subscribe(new Observer<String>() {
            @Override
            public void onSubscribe(Disposable d) {
                Log.d("----", "onSubscribe");
            }

            @Override
            public void onNext(String s) {
                Log.d("----", s);
            }

            @Override
            public void onError(Throwable e) {
                Log.d("----", "onError");
            }

            @Override
            public void onComplete() {
                Log.d("----", "onComplete");
            }
        });

在 RxJava 的默認規則中,事件的發出和消費都是在同一個線程的。也就是說,如果只用上面的方法,實現出來的只是一個同步的觀察者模式。觀察者模式本身的目的就是『后臺處理,前臺回調』的異步機制,因此異步對于 RxJava 是至關重要的。而要實現異步,則需要用到 RxJava 的另一個概念: Scheduler 。

先貼代碼,以下便可實現異步操作:

Observable.create(new ObservableOnSubscribe<String>() {
            @Override
            public void subscribe(ObservableEmitter<String> emitter) throws Exception {
                emitter.onNext("rxjava");
                emitter.onComplete();
            }
        }).subscribeOn(Schedulers.newThread())
          .observeOn(AndroidSchedulers.mainThread())      
          .subscribe(new Observer<String>() {
            @Override
            public void onSubscribe(Disposable d) {
                Log.d("----", "onSubscribe");
            }

            @Override
            public void onNext(String s) {
                Log.d("----", s);
            }

            @Override
            public void onError(Throwable e) {
                Log.d("----", "onError");
            }

            @Override
            public void onComplete() {
                Log.d("----", "onComplete");
            }
        });

在這里我們使用了Scheduler 進行了線程的切換,接下來介紹一下Scheduler :

  1. Scheduler (線程切換)

在不指定線程的情況下, RxJava 遵循的是線程不變的原則,即:在哪個線程調用 subscribe(),就在哪個線程生產事件;在哪個線程生產事件,就在哪個線程消費事件。如果需要切換線程,就需要用到 Scheduler (調度器)。

RxJava 已經內置了幾個 Scheduler :

  • Schedulers.newThread(): 總是啟用新線程,并在新線程執行操作。
  • Schedulers.io(): I/O 操作(讀寫文件、讀寫數據庫、網絡信息交互等)所使用的 Scheduler。行為模式和 newThread() 差不多,區別在于 io() 的內部實現是是用一個無數量上限的線程池,可以重用空閑的線程,因此多數情況下 io() 比 newThread() 更有效率。不要把計算工作放在 io() 中,可以避免創建不必要的線程。
  • Schedulers.computation(): 計算所使用的 Scheduler。這個計算指的是 CPU 密集型計算,即不會被 I/O 等操作限制性能的操作,例如圖形的計算。這個 Scheduler 使用的固定的線程池,大小為 CPU 核數。不要把 I/O 操作放在 computation() 中,否則 I/O 操作的等待時間會浪費 CPU。
  • AndroidSchedulers.mainThread(),它指定的操作將在 Android 主線程運行

有了這幾個 Scheduler ,就可以使用 subscribeOn() 和 observeOn() 兩個方法來對線程進行控制了。

  • subscribeOn(): 指定 subscribe() 所發生的線程,即 Observable.OnSubscribe 被激活時所處的線程。或者叫做事件產生的線程。
  • observeOn(): 指定 Subscriber 所運行在的線程。或者叫做事件消費的線程。

簡單使用如下:

Observable.create(new ObservableOnSubscribe<String>() {
            @Override
            public void subscribe(ObservableEmitter<String> emitter) throws Exception {
                emitter.onNext("1");
                emitter.onNext("2");
                emitter.onNext("3");
                emitter.onComplete();
            }
        }).subscribeOn(Schedulers.io()) //在io執行上述操作
          .observeOn(AndroidSchedulers.mainThread())//在UI線程執行下面操作
          .subscribe(new Observer<String>() {
            @Override
            public void onSubscribe(Disposable d) {
                Log.d("----","開始了");
            }

            @Override
            public void onNext(String s) {
                Log.d("----", s);
            }

            @Override
            public void onError(Throwable e) {

            }

            @Override
            public void onComplete() {
                Log.d("----", "complete");
            }
        });

以上就是Rxjava的基本常用方法了,看到這里你就已經可以愉快的使用Rxjava代替AsyncTask / Handler了,趕緊去試試吧!

  • 參考文章: 給 Android 開發者的 RxJava 詳解 ,這是扔物線很早之前寫的一篇關于Rxjava 1.x的詳解,雖然現在已經Rxjava已經發展到2.x版本了.但其中一些基本實現原理的講解確實非常到位,通俗易懂,很適合初學者學習,強烈建議去看下
  • RxJava2 只看這一篇文章就夠了 這是玉剛說的一篇關于Rxjava常用API的介紹,基本囊括了Rxjava所用到的所有API,還有代碼舉例,也是強烈建議觀看收藏

關于Rxjava系列一就到此結束啦,后面有時間我還會寫寫一些其他的常用拓展操作符和與retrofit2的結合使用,歡迎關注訂閱!

歡迎關注作者 darryrzhong ,更多干貨等你來拿喲.

請賞個小紅心!因為你的鼓勵是我寫作的最大動力!

更多精彩文章請關注

原文 

https://segmentfault.com/a/1190000019508999

本站部分文章源于互聯網,本著傳播知識、有益學習和研究的目的進行的轉載,為網友免費提供。如有著作權人或出版方提出異議,本站將立即刪除。如果您對文章轉載有任何疑問請告之我們,以便我們及時糾正。

PS:推薦一個微信公眾號: askHarries 或者qq群:474807195,里面會分享一些資深架構師錄制的視頻錄像:有Spring,MyBatis,Netty源碼分析,高并發、高性能、分布式、微服務架構的原理,JVM性能優化這些成為架構師必備的知識體系。還能領取免費的學習資源,目前受益良多

轉載請注明原文出處:Harries Blog? » Android RxJava系列一: 基礎常用詳解

贊 (0)
分享到:更多 ()

評論 0

  • 昵稱 (必填)
  • 郵箱 (必填)
  • 網址
2013平特肖公式