RxJava的學習(附demo)

什麼是Rx

Rx是一個函數庫,讓開發者可以利用可觀察序列和LINQ風格查詢操作符來編寫異步和基於事件的程序。簡單來講Rx就是一種響應式編程,來創建基於事件的異步程序

RxJava 到底是什麼

RxJava 在 GitHub 主頁上的自我介紹是 "a library for composing asynchronous and event-based programs using observable sequences for the Java VM"也就是官方定義:一個在 Java VM 上使用可觀測的序列來組成異步的、基於事件的程序的庫。

然而,對於初學者來說,這太難看懂了。因爲它是一個『總結』,而初學者更需要一個『引言』。

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

RxJava 的異步實現,是通過一種擴展的觀察者模式來實現的。

觀察者模式

  • 普通的觀察者模式:

其中這個Button就是被觀察者(Observable),OnClickListener就是觀察者(Observer),兩者通過setOnClickListener達成訂閱(Subscribe)關係,之後當Button產生OnClick事件的時候,會直接發送給OnClickListener,它做出相應的響應處理。
  • RxJava的觀察者模式呢,跟這個差不多,但是也有幾點差別:
Observer與Observable是通過 subscribe() 來達成訂閱關係。
RxJava中事件回調有三種:onNext() 、 onCompleted() 、 onError() 。
如果一個Observerble沒有任何的Observer,那麼這個Observable是不會發出任何事件的。

關於RxJava的回調事件:

  • onNext():基本事件。
  • onCompleted(): 事件隊列完結。RxJava 不僅把每個事件單獨處理,還會把它們看做一個隊列。RxJava 規定,當不會再有新的 onNext() 發出時,需要觸發 onCompleted() 方法作爲標誌。
  • onError(): 事件隊列異常。在事件處理過程中出異常時,onError() 會被觸發,同時隊列自動終止,不允許再有事件發出。
值得注意的是在一個正確運行的事件序列中, onCompleted() 和 onError() 有且只有一個,並且是事件序列中的最後一個。如果在隊列中調用了其中一個,就不應該再調用另一個。

RxJava 好在哪

換句話說,『同樣是做異步,爲什麼人們用它,而不用現成的 AsyncTask / Handler / XXX / ... ?』

異步操作很關鍵的一點是程序的簡潔性,因爲在調度過程比較複雜的情況下,異步代碼經常會既難寫也難被讀懂。 Android 創造的 AsyncTask 和Handler ,其實都是爲了讓異步代碼更加簡潔。RxJava 的優勢也是簡潔,但它的簡潔的與衆不同之處在於,隨着程序邏輯變得越來越複雜,它依然能夠保持簡潔。

如何實現RxJava

  • 創建Observer
這裏我們new一個Observer出來,其實就是實現Observer的接口,注意String是接收參數的類型:
//1.創建觀察者對象
        Observer<String> observer=new Observer<String>() {
            @Override
            public void onCompleted() {
                Log.e("kaka","onComlieted");
            }

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

            @Override
            public void onNext(String s) {
                Log.e("kaka","onNext");

            }
        };

當然這裏也要提另外一個接口:Subscriber ,一個實現了 Observer 的抽象類:Subscriber。 Subscriber 對 Observer 接口進行了一些擴展,但他們的基本使用方式是完全一樣的,實質上,在 RxJava 的 subscribe 過程中,Observer 也總是會先被轉換成一個 Subscriber 再使用。
  • 創建Observable
與Observer不同的是,Observable是通過 create() 方法來創建的。注意String是發送參數的類型:
//2.創建被觀察者對象
        Observable<String> observable=Observable.create(new Observable.OnSubscribe<String>() {
            @Override
            public void call(Subscriber<? super String> subscriber) {
                subscriber.onNext("hi");
                subscriber.onNext("nihao");
                subscriber.onNext("kaka");
                subscriber.onCompleted();
            }
        });

  • 現在就需要用 subscribe() 方法來將它們連接起來,形成一種訂閱關係:
        observable.subscribe(observer);

這裏其實確實有點奇怪,爲什麼是Observable(被觀察者)訂閱了Observer(觀察者)呢?其實我們想一想之前Button的點擊事件:

Button.setOnClickListener(new View.OnClickListener())

Button是被觀察者,OnClickListener是觀察者,setOnClickListener是訂閱。我們驚訝地發現,也是被觀察者訂閱了觀察者,所以應該是一種流式API的設計吧,也沒啥影響。
運行結果:

線程控制——Scheduler

在RxJava中,Scheduler相當於線程控制器,可以通過它來指定每一段代碼運行的線程。

RxJava已經內置了幾個Scheduler

Schedulers.immediate(): 直接在當前線程運行,相當於不指定線程。這是默認的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專用線程,指定操作在主線程運行。(需要導入RxAndroid依賴)

那我們如何切換線程呢?RxJava中提供了兩個方法:subscribeOn() 和 observeOn() ,兩者的不同點在於:

subscribeOn(): 指定subscribe()訂閱所發生的線程,即 call() 執行的線程。或者叫做事件產生的線程。

observeOn(): 指定Observer所運行在的線程,即onNext()執行的線程。或者叫做事件消費的線程。

 Observable.just("hi","nihao","woshi")
                .subscribeOn(Schedulers.io())//被創建的事件內容"hi","nihao","woshi"將會在io線程發出
                .observeOn(AndroidSchedulers.mainThread())//字符串的打印將發生在主線程
                .subscribe(new Action1<String>() {
                    @Override
                    public void call(String s) {
                        Log.e("kaka",s);
                    }
                });



一個基於RxJava的Demo

/**
     * 點擊按鈕,imageview顯示圖片
     *
     * @param view
     */

    public void downloadImg(View view) {
        Observable.create(new Observable.OnSubscribe<Bitmap>() {
            @Override
            public void call(Subscriber<? super Bitmap> subscriber) {
                subscriber.onNext(GetBitmapForUrl.getBitmap(url));//通過URL得到圖片的bitmap對象
            }
        })
                .subscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(new Observer<Bitmap>() {
                    @Override
                    public void onCompleted() {

                    }

                    @Override
                    public void onError(Throwable e) {

                    }

                    @Override
                    public void onNext(Bitmap bitmap) {
                        imageView.setImageBitmap(bitmap);

                    }
                });
    }

運行結果:



幾篇關於RxJava的文章:
Rx系列之RxJava操作符:http://www.jianshu.com/p/30e13d874a61
Rx系列之Rxjava操作符進階-使用場景:http://www.jianshu.com/p/79cb4e1c9771

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章