RxJava入門

項目小版本上線,抽空簡單學習了下久仰大名的RxJavahtml

 

1、引入
我的以爲rxjava的特色:
  1. 強大靈活的事件流處理(多線程/多事件/複合對象)
  2. 強大靈活優雅簡潔的異步
  3. 鏈式調用
  4. 可自動Lambda化
 
實現:RxJava 是經過一種擴展的觀察者模式來實現的
類比 類比 實際 實際 職責
演講者 Button
(可)被訂閱者
(同右)
(可)被觀察者
Observable
決定何時觸發事件以及觸發怎樣的事件
聽衆 OnClickListener
訂閱者
Subscriber
觀察者
Observer
決定事件觸發的時候將有怎樣的行爲
買票 setOnClickListener()
訂閱
subscribe
註冊  
命令 onClick() 事件 事件  
演講者只有Observable一種類,可是聽衆有Subscriber和Observer兩種類,有點跟演講者一個聽衆不少相似
 
與傳統觀察者模式不一樣, RxJava 的事件回調方法除了普通事件 onNext() (至關於 onClick() / onEvent())以外,還定義了兩個特殊的事件:onCompleted() 和 onError()。
  1. 不少onNext()
  2. onCompleted(): 事件隊列完結。RxJava 不只把每一個事件單獨處理,還會把它們看作一個隊列。RxJava 規定,當不會再有新的onNext() 發出時,須要觸發 onCompleted() 方法做爲標誌。
  3. onError(): 事件隊列異常。在事件處理過程當中出異常時,onError() 會被觸發,同時隊列自動終止,不容許再有事件發出。
在一個正確運行的事件序列中, onCompleted() 和 onError() 有且只有一個,而且是事件序列中的最後一個。須要注意的是,onCompleted() 和 onError() 兩者也是互斥的,即在隊列中調用了其中一個,就不該該再調用另外一個。
 
 

2、實現方式
步驟:
  1. 建立演講者
  2. 建立聽衆
  3. 買票
 
一、建立演講者
建立演講者的方式有點特殊,它不是經過new的方法,而是經過一系列不一樣的內部靜態工廠方法來建立的,最普通的有create( ) 方法
 
1.1.create( ) 方法建立
  1. 不是經過new的方法,而是一個內部靜態工廠方法create( )來建立,這個方法須要傳入一個 OnSubscribe 對象做爲參數
    1. 不過換個角度,把它當成一個須要傳入一個參數的構造方法就行了(雖然內部是有點其餘貨的)
  2. 方法具體是:Observable<T>   create ( OnSubscribe<T> f )
  3. 這個  OnSubscribe 類自己是Observable的內部類
    1. 這個對象在create( )時傳入後會存儲在返回的 Observable 對象中
    2. 當 Observable 被訂閱的時候,OnSubscribe 的 call() 方法會自動被調用
    3. 這個call方法會遍歷傳入全部的聽衆o,這些聽衆都實現了聽衆的那三個約定方法,在這裏就能夠執行本身須要的業務代碼,並在須要的時候回調聽衆的那三個約定方法
    4. 換個角度說,OnSubscribe 的做用至關於一個計劃表或者說事件發生器
    5. 這個泛型T是輸出類型,也就是會傳給聽衆的類型
 
簡寫:
Observable observable = Observable.create(new OnSubscribe() {
    @Override
    public void call(Object o) {

    }
});
具體的實際的寫法:
  1. 傳入聽衆的表示格式是這樣:Subscriber<? super String> subscriber(前面的泛型是string類)
  2. 這個例子很簡單:
    1. 事件的內容是字符串,而不是一些複雜的對象
    2. 事件的內容是已經定好了的,而不像有的觀察者模式同樣是待肯定的(例如網絡請求的結果在請求返回以前是未知的)
    3. 全部事件在一瞬間被所有發送出去,而不是夾雜一些肯定或不肯定的時間間隔或者通過某種觸發器來觸發的
 
Observable observable = Observable.create(new Observable.OnSubscribe<String>() {
    @Override
    public void call(Subscriber<? super String> subscriber) {
        subscriber.onNext("Hello");
        subscriber.onNext("Hi");
        subscriber.onCompleted();
    }
});
 
1.2.兩個快捷建立靜態工廠方法 just( ) , from( )
1.2.1.Observable<T>   just( T t1, T t2 )
  1. 這個方法有10個重載,分別能夠傳入1個到10個參數(orz)
  2. 這是一個簡便方法,會將傳入的參數依次發送出來
  3. 能夠寫成基本的 create( ) 形式
 
Observable observable = Observable.just("Hello", "Hi");
等於上面的 create( ):
Observable observable = Observable.create(new Observable.OnSubscribe<String>() {
    @Override
    public void call(Subscriber<? super String> subscriber) {
        subscriber.onNext("Hello");
        subscriber.onNext("Hi");
        subscriber.onCompleted();
    }
});
 
1.2.2.
Observable<T>   from( T[ ]  array )
Observable<T>   from( Iterable<? extends T>  array )
  1. 將傳入的數組或 Iterable 拆分紅具體對象後,依次發送出來
  2. 能夠寫成基本的 create( ) 形式
 
String[] words = {"Hello", "Hi"};
Observable observable = Observable.from(words);
 
二、建立聽衆
這個有幾種方式
2.1.經過rx包中的 Observer 接口
  1. 注意不是java中util包中的接口
Observer<String> observer = new Observer<String>() {
    @Override
    public void onNext(String s) {}
    @Override
    public void onCompleted() {}
    @Override
    public void onError(Throwable e) {}
};
 
2.2.經過rx包中的 Subscriber 抽象類[推薦]
  1. 它實現了 Observer 接口,並進行了一些擴展
  2. 使用方法跟Observer同樣,並且必須實現的方法就是 Observer 接口中的方法,在訂閱(subscribe)的時候,Observer 也老是會先被轉換成一個 Subscriber 再使用,因此基本建議能夠用Observer的地方都用Subscriber吧
  3. 這個抽象類擴展了兩個可選的方法:
    1. onStart( )
      1. 它會在 subscribe 剛開始,而事件還未發送以前被調用,能夠用於作一些準備工做,例如數據的清零或重置
      2. 須要注意的是,若是對準備工做的線程有要求(例如彈出一個顯示進度的對話框,這必須在主線程執行), onStart() 就不適用了,由於它老是在 subscribe 所發生的線程被調用,而不能指定線程。要在指定的線程來作準備工做,可使用 doOnSubscribe() 方法
    2. unsubscribe( )
      1. 這個方法用於取消訂閱。在這個方法被調用後,Subscriber 將再也不接收事件
      2. 通常在這個方法調用前,可使用 isUnsubscribed() 先判斷一下狀態
      3. unsubscribe() 這個方法很重要,由於在 subscribe() 以後, Observable 會持有 Subscriber 的引用,這個引用若是不能及時被釋放,將有內存泄露的風險。因此最好保持一個原則:要在再也不使用的時候儘快在合適的地方(例如 onPause() onStop() 等方法中)調用unsubscribe() 來解除引用關係,以免內存泄露的發生
  4. 這個泛型T是輸入類型,也就是聽衆能接收的類型
Subscriber<String> subscriber = new Subscriber<String>() {
    @Override
    public void onNext(String s) {}
    @Override
    public void onCompleted() {}
    @Override
    public void onError(Throwable e) {}
};
 
2.3.快捷建立方法:ActionX 接口[推薦]
聽衆也有快捷的建立方式,那就是經過ActionX 接口
  1. ActionX 接口有不少,Action0 和 Action1 最經常使用,還有Action2, Action3,X表明傳入的參數的數目
  2. 他們實際上是對具備不一樣傳入參數、可是無返回值的方法的包裝接口
  3. subscribe()會根據這些ActionX對象生成正常的Subscriber
 
以0和1爲例
  1. Action0
    1. Action0 是 RxJava 的一個接口,它只有一個方法 call(),這個方法是無參無返回值的
    2. 因爲 onCompleted() 方法也是無參無返回值的,所以 Action0 能夠被當成一個包裝對象,將 onCompleted() 的內容打包起來將本身做爲一個參數傳入 subscribe() 以實現不完整定義的回調
    3. 這樣其實也能夠看作將 onCompleted() 方法做爲參數傳進了subscribe(),至關於其餘某些語言中的『閉包』
  2. Action1
    1. Action1 也是一個接口,它一樣只有一個方法 call(T param),這個方法也無返回值,但有一個參數;
    2. 與 Action0 同理,因爲 onNext(T obj) 和 onError(Throwable error) 也是單參數無返回值的,所以 Action1能夠將 onNext(obj) 和 onError(error) 打包起來傳入 subscribe() 以實現不完整定義的回調
 
正常使用方式是:
  1. new 出 action 對象
  2. 組合塞進 subsribe 方法
經過Action0、Action1構造三種方法的包裝對象
 
// onNext()
Action1<String> action1 = new Action1<String>() {
    @Override
    public void call(String s) {}
};

// onError()
Action1<Throwable> action2 = new Action1<Throwable>() {
    @Override
    public void call(Throwable throwable) {}
};

// onCompleted()
Action0 action3 = new Action0() {
    @Override
    public void call() {}
};
// 自動建立 Subscriber ,並使用 action1 來定義 onNext()
observable.subscribe(action1);

// 自動建立 Subscriber ,並使用 action1 和 action2 來定義 onNext() 和 onError()
observable.subscribe(action1, action2);

// 自動建立 Subscriber ,並使用 action一、 action2 和 action3 來定義 onNext()、 onError() 和 onCompleted()
observable.subscribe(action1, action2, action3);
 
若是隻是要onNext( ) ,這樣使用匿名類也很清晰
Observable.just("1","2","3")
        .subscribe(new Action1<String>() {
            @Override
            public void call(String name) {
                Log.d(tag, name);
            }
        });
 
 
三、買票(進行訂閱)
建立了 Observable 和 Observer 以後,再用 subscribe() 方法將它們聯結起來,整條鏈子就能夠工做了
 
代碼形式很簡單:
observable.subscribe(subscriber);
  1. 有人可能會注意到, subscribe() 這個方法有點怪:它看起來是『observalbe 訂閱了 subscriber』而不是『subscriber 訂閱了 observalbe』,這看起來就像『雜誌訂閱了讀者』同樣顛倒了對象關係。這讓人讀起來有點彆扭
  2. 由於若是把 API 設計成 subscriber.subscribe(observable) ,雖然更加符合思惟邏輯,但對流式 API 的設計就形成影響了,由於對於流事件,是有一個生產者和一系列消費者的,因此生產者放前邊,後邊跟一串消費者纔是更流的形式
  3. 這種形式其實跟普通的java觀察者模式很像,演講者.add(聽衆)
 
 

3、快速使用及舉例
 
使用rxjava首先是引入依賴:
1.基本的rxjava:
compile 'io.reactivex:rxjava:1.0.14'
2.帶android特性的rxjava:
compile 'io.reactivex:rxandroid:1.0.1'
3.支持rxjava的網絡加載庫retrofit
compile 'com.squareup.retrofit:retrofit:1.9.0'
 
而後幾個簡單的例子:
1.真正最簡單的例子:打印幾個字符串
  1. 三步走
  2. 最簡單的just方法
  3. 一個普通的subscriber
Observable.just("1","2","3").subscribe(new Subscriber<String>() {
    @Override
    public void onNext(String s) {
        Log.d(tag, s);
    }
    @Override
    public void onCompleted() {}
    @Override
    public void onError(Throwable e) {}
});
 
2.複雜一點點:給ImageView set 圖片
  1. 需求:
  2. 實現:
    1. 仍是基本的三步走,稍微注意下格式(流式結構)
final Drawable drawable = getActivity().getResources().getDrawable(R.drawable.1);
final ImageView imageView = new ImageView(getActivity());

Observable.create(new Observable.OnSubscribe<Drawable>() {
    @Override
    public void call(Subscriber<? super Drawable> subscriber) {
        subscriber.onNext(drawable);
        subscriber.onCompleted();
    }
}).subscribe(new Subscriber<Drawable>() {
    @Override
    public void onNext(Drawable drawable) {
        imageView.setImageDrawable(drawable);
    }

    @Override
    public void onCompleted() {}

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

4、線程控制:Scheduler 和 subscribeOn()、observeOn()
  1. 在不指定線程的狀況下, RxJava 遵循的是線程不變的原則
  2. 即:在哪一個線程調用 subscribe(),就在哪一個線程生產事件;在哪一個線程生產事件,就在哪一個線程消費事件。
  3. 若是須要切換線程,就須要用到 Scheduler (調度器)
 
1.Scheduler
RxJava 經過Scheduler來指定每一段代碼應該運行在什麼樣的線程
RxJava 已經內置了幾個 Scheduler ,它們已經適合大多數的使用場景:
  1. Schedulers.immediate()
    1. 直接在當前線程運行,至關於不指定線程
    2. 這是默認的 Scheduler
  2. Schedulers.newThread()
    1. 老是啓用新線程,並在新線程執行操做
  3. Schedulers.io( )
    1. I/O 操做(讀寫文件、讀寫數據庫、網絡信息交互等)所使用的 Scheduler
    2. 行爲模式和 newThread() 差很少,區別在於 io() 的內部實現是是用一個無數量上限的線程池,能夠重用空閒的線程,所以多數狀況下 io() 比 newThread() 更有效率
    3. 不要把計算工做放在 io() 中,能夠避免建立沒必要要的線程
  4. Schedulers.computation( )
    1. 計算所使用的 Scheduler,這個計算指的是 CPU 密集型計算,即不會被 I/O 等操做限制性能的操做,例如圖形的計算
    2. 這個 Scheduler 使用的固定的線程池,大小爲 CPU 核數
    3. 不要把 I/O 操做放在 computation() 中,不然 I/O 操做的等待時間會浪費 CPU
  5.  Android 還有一個專用的 AndroidSchedulers.mainThread()
    1. 它指定的操做將在 Android 主線程運行
 
2.subscribeOn() 和 observeOn()
有了這幾個 Scheduler ,就可使用 subscribeOn() 和 observeOn() 兩個方法來對線程進行控制了
  1. subscribeOn( )
    1. 指定 subscribe() 所發生的線程,即 Observable.OnSubscribe 被激活時所處的線程
    2. 而這其實就是事件產生的線程,也就是Observable活動的線程
    3. (看到這難免有點亂,Observable活動在subscribeOn指定的線程,那這裏就只能用[Observable.OnSubscribe 被激活]這件事來記了)
  2. observeOn( )
    1. 指定 Subscriber 所運行在的線程。或者叫作事件消費的線程
    2. (一樣正好相反)
 
3.例子
Observable.just(1, 2, 3, 4)
        .subscribeOn(Schedulers.io())                // 指定 subscribe() 發生在 IO 線程
        .observeOn(AndroidSchedulers.mainThread())   // 指定 Subscriber 的回調發生在主線程
        .subscribe(new Action1<Integer>() {
            @Override
            public void call(Integer number) {
                Log.d(tag, "number:" + number);
            }
        });
  1. 這種在subscribe() 以前寫上兩句 subscribeOn(Scheduler.io()) 和 observeOn(AndroidSchedulers.mainThread()) 的使用方式很是套路
  2. 它適用於多數的 『後臺線程取數據,主線程顯示』的程序策略
  3. 前面加載圖片的代碼中應該要加上這兩句的
 
4.拓展
4.1.事件消費的線程可屢次變換
  1. observeOn() 指定的是 Subscriber 的線程,而這個 Subscriber 不必定是最終subscribe() 時的Subscriber ,而是 observeOn() 執行時的當前 Observable 所對應的 Subscriber ,即它的直接下級 Subscriber
  2. 換句話說,observeOn() 指定的是它以後的操做所在的線程
  3. 所以若是有屢次切換線程的需求,只要在每一個想要切換線程的位置調用一次 observeOn() 便可
  4. 以下,經過 observeOn() 的屢次調用,程序實現了線程的屢次切換
Observable.just(1, 2, 3, 4)            // IO 線程,由 subscribeOn() 指定
        .subscribeOn(Schedulers.io())
        .observeOn(Schedulers.newThread())
        .map(mapOperator1)             // 新線程,由 observeOn() 指定
        .observeOn(Schedulers.io())
        .map(mapOperator2)             // IO 線程,由 observeOn() 指定
        .observeOn(AndroidSchedulers.mainThread())
        .subscribe(subscriber);        // Android 主線程,由 observeOn() 指定
 
4.2.事件產生線程是固定的
不一樣於 observeOn() , subscribeOn() 的位置雖然放在哪裏均可以,但它是隻能調用一次
當使用了多個subscribeOn() 的時候,只有第一個 subscribeOn() 起做用
 
4.3.流程開始前的初始化問題:【Subscriber 的 onStart( )】【Observable 的 doOnSubscribe( )】
  1. 在前面講 Subscriber 的時候,提到過 Subscriber 的 onStart() 能夠用做流程開始前的初始化
  2. 然而 onStart() 因爲在subscribe() 發生時就被調用了,也就是沒有被observeOn() 指定線程,所以是執行在 subscribe() 被調用時的線程也就是原線程
  3. 這就致使若是 onStart() 中含有對線程有要求的代碼(例如在界面上顯示一個 ProgressBar,這必須在主線程執行),將會有線程非法的風險,由於有時你沒法預測subscribe() 將會在什麼線程執行
 
解決方法
  1. Observable(不是Subscriber的)有一個方法doOnSubscribe()
  2. 它和 Subscriber.onStart() 一樣是在subscribe() 調用後並且在事件發送前執行,但區別在於它能夠指定線程
  3. 默認狀況下, doOnSubscribe() 執行在 subscribe() 發生的線程
  4. 而若是在 doOnSubscribe() 以後有 subscribeOn() 的話,它將執行在離它最近的 subscribeOn() 所指定的線程
Observable.create(onSubscribe)
        .subscribeOn(Schedulers.io())
        .doOnSubscribe(new Action0() {
            @Override
            public void call() {
                progressBar.setVisibility(View.VISIBLE);  // 須要在主線程執行
            }
        })
        .subscribeOn(AndroidSchedulers.mainThread())      // 指定主線程
        .observeOn(AndroidSchedulers.mainThread())
        .subscribe(subscriber);
 

5、變換
  1. RxJava 提供了對事件序列進行變換的支持,這是它的核心功能之一,也是大多數人說『RxJava 真是太好用了』的最大緣由
  2. 所謂變換,就是將事件序列中的對象整個事件隊列進行加工處理,轉換成不一樣的事件或事件序列
 
變換節點是由一個【變換算法】和一個【變換樞紐】構成的
  1. 變換算法是一系列方法,好比:map()、flatMap(),他們決定變換的方式,是隨方法固定的
  2. 變換樞紐是一種相似管道樞紐的容器,裏邊由你寫具體的變換細節;輸入和輸出就像管道,如何分流就像管道的佈線
  3. 往一個變換算法裏傳入一個變換樞紐就組成了一個變換節點
 
1.變換樞紐
  1. 變換樞紐是FuncX系列接口的對象
  2. FuncX系列接口跟前面講的ActionX系列接口很是像
    1. 他們是位於 rx.functions 包下的所有兩個系列接口
    2. ActionX系列是能夠傳入1個或多個參數,可是無返回值的call方法的包裝
    3. FuncX系列是能夠傳入1個或多個參數,可是有一個返回值的call方法的包裝
  3. 正是兩個方法的惟一區別(是否有返回值)決定了在rx鏈中二者不一樣的角色
    1. ActionX系列因爲沒有返回值,因此只能做爲鏈的終點,也就是爲觀衆服務,能夠被組合構成觀衆
    2. FuncX系列因爲有返回值,但他又不能做爲鏈的起點,因此就天然成了咱們這裏要說的新角色:鏈的中繼者,或者說變換器
  4. FuncX系列的泛型位置是這樣:前面的全部參數是輸入參數,最後一個參數是輸出參數
 
2.變換算法
2.1.map( )
  1. map() 方法將參數中的 String 對象轉換成一個 Bitmap 對象後返回
  2. 在通過 map() 方法後,事件的參數類型也由 String轉爲了 Bitmap
Observable.just("images/logo.png")                  // 輸入類型 String
        .map(new Func1<String, Bitmap>() {
            @Override
            public Bitmap call(String filePath) {   // 參數類型 String
                return getBitmapFromPath(filePath); // 返回類型 Bitmap
            }
        })
        .subscribe(new Action1<Bitmap>() {
            @Override
            public void call(Bitmap bitmap) {       // 參數類型 Bitmap
                showBitmap(bitmap);
            }
        });
 
2.2.flatMap( )
這是一個頗有用但不太好難理解的變換
 
2.2.1.情景推導
首先假設這麼一種需求:有一個數據結構『學生』,如今須要打印出一組學生的名字
用上面提到的map方法實現起來很簡單:
Student[] students = new Student[10];
Observable.from(students)
        .map(new Func1<Student, String>() {
            @Override
            public String call(Student student) {
                return student.getName();
            }
        })
        .subscribe(new Subscriber<String>() {
            @Override
            public void onNext(String name) {
                Log.d(tag, name);
            }
            ...
        });
 
再假設:若是要打印出每一個學生所須要修的全部課程的名稱呢?(需求的區別在於,每一個學生只有一個名字,但卻有多個課程)
這個時候用不了map了,先用普通方式實現一下:
Student[] students = new Student[10];
Observable.from(students)
        .subscribe(new Subscriber<Student>() {
            @Override
            public void onNext(Student student) {
                List<Course> courses = student.getCourses();
                for (int i = 0; i < courses.size(); i++) {
                    Course course = courses.get(i);
                    Log.d(tag, course.getName());
                }
            }
            ...
        });
 
2.2.2.引入
  1. 上面實現卻是實現了,可是這個for循環的存在難免顯得有點不太優雅
  2. 若是不想在 Subscriber 中使用 for 循環,而是但願在 Subscriber 中直接接收單個的 Course 對象呢(這對於代碼複用很重要)?
  3. 用 map() 顯然是不行的,由於 map() 是一對一的轉化,而我如今的要求是一對多的轉化。那怎麼才能把一個 Student 轉化成多個 Course 呢?
  4. 這個時候,就須要用 flatMap( ) 了
 
2.2.3.實現
Student[] students = new Student[10];
Observable.from(students)
        .flatMap(new Func1<Student, Observable<Course>>() {
            @Override
            public Observable<Course> call(Student student) {
                return Observable.from(student.getCourses());
            }
        })
        .subscribe(new Subscriber<Course>() {
            @Override
            public void onNext(Course course) {
                Log.d(tag, course.getName());
            }
            ...
        });
  1. flatMap() 和 map() 有一個相同點:也是把傳入的參數轉化以後返回另外一個對象
  2. 不一樣的是, flatMap() 中返回的是個 Observable 對象,而且這個 Observable 對象並非被直接發送到了 Subscriber 的回調方法中,而是
    1. 先使用傳入的事件對象建立一個 Observable 對象
    2. 可是並不發送這個 Observable, 而是將它激活(subscribe),因而它開始發送事件
    3. 每個建立出來的子Observable 發送的事件,都被匯入同一個 Observable ,而這個 Observable 負責將這些事件統一交給 Subscriber 的回調方法
  3. 上面這三個步驟,把事件拆成了兩級,經過一組新建立的 Observable 將初始的對象『鋪平』以後經過統一路徑分發了下去
    1. 這個『鋪平』就是 flatMap() 所謂的 flat
    2. 每一個list就像捲起的紙,flatMap就是把一卷捲紙展開再連在一塊兒
 
2.3.throttleFirst( )
在每次事件觸發後的必定時間間隔內丟棄新的事件。經常使用做去抖動過濾,例如按鈕的點擊監聽器
媽媽不再怕個人用戶手抖點開兩個重複的界面啦
RxView.clickEvents(button)                         // RxBinding 代碼,後面的文章有解釋
        .throttleFirst(500, TimeUnit.MILLISECONDS) // 設置防抖間隔爲 500ms
        .subscribe(subscriber);
 

6、應用
1.Retrofit
 
2. RxBinding
  1. RxBinding 是 Jake Wharton 的一個開源庫,它提供了一套在 Android 平臺上的基於 RxJava 的 Binding API
  2. 所謂 Binding,就是相似設置 OnClickListener 、設置 TextWatcher 這樣的註冊綁定對象的 API
 
舉個設置點擊監聽的例子。使用 RxBinding ,能夠把事件監聽用這樣的方法來設置:
Button button = ...;
RxView.clickEvents(button)         // 以 Observable 形式來反饋點擊事件
        .subscribe(new Action1<ViewClickEvent>() {
            @Override
            public void call(ViewClickEvent event) {
               
            }
        });
 
看起來除了形式變了沒什麼區別,實質上也是這樣。甚至若是你看一下它的源碼,你會發現它連實現都沒什麼驚喜:它的內部是直接用一個包裹着的 setOnClickListener() 來實現的。
然而,僅僅這一個形式的改變,卻剛好就是 RxBinding 的目的:擴展性。
經過RxBinding 把點擊監聽轉換成 Observable 以後,就有了對它進行擴展的可能。
擴展的方式有不少,根據需求而定。一個例子是前面提到過的 throttleFirst() ,用於去抖動,也就是消除手抖致使的快速連環點擊:
RxView.clickEvents(button)
        .throttleFirst(500, TimeUnit.MILLISECONDS)
        .subscribe(clickAction);
 
3. 各類異步操做
前面舉的 Retrofit 和 RxBinding 的例子,是兩個能夠提供現成的 Observable 的庫。而若是你有某些異步操做沒法用這些庫來自動生成 Observable,也徹底能夠本身寫。例如數據庫的讀寫、大圖片的載入、文件壓縮/解壓等各類須要放在後臺工做的耗時操做,均可以用 RxJava 來實現,有了以前幾章的例子,這裏應該不用再舉例了。
 
4. RxBus
RxBus 名字看起來像一個庫,但它並非一個庫,而是一種模式,它的思想是使用 RxJava 來實現了 EventBus ,而讓你再也不須要使用Otto 或者 GreenRobot 的 EventBus。至於什麼是 RxBus,能夠看這篇文章。順便說一句,Flipboard 已經用 RxBus 替換掉了 Otto,目前爲止沒有不良反應。
 
 

附錄
 
1.關於觀察者模式
其實以爲這個名字很是容易誤解:觀察者模式裏兩個角色,觀察者和被觀察者,兩個方面會讓人誤解:
  1. 主被動關係,每每會有人以爲觀察者是主動觀察,其實否則
  2. 名字就是一字之差,容易混淆,形成理解障礙
第二點就不說了,來討論下第一點,其實裏邊一個是事件發出者,一個是被事件驅動者,主被動關係是反過來的,應該是 主人和僕人,指揮官和小兵,演講者和聽衆,button和onclicklistener 的關係,觀察者實際上是被動觸發的,而不是主動觀察
 
觀察者模式用button和onclicklistener的模型來類比真是很是形象好理解(由於:1經常使用,平易近人;2很是符合)
對設置 OnClickListener 來講, View 是被觀察者, OnClickListener 是觀察者,兩者經過 setOnClickListener() 方法達成訂閱關係。訂閱以後用戶點擊按鈕的瞬間,Android Framework 就會將點擊事件發送給已經註冊的 OnClickListener 。採起這樣被動的觀察方式,既省去了反覆檢索狀態的資源消耗,也可以獲得最高的反饋速度。
    1. Button -> 被觀察者
    2. OnClickListener -> 觀察者
    3. setOnClickListener() -> 訂閱
    4. onClick() -> 事件

 

參考資料:http://www.jcodecraeer.com/a/anzhuokaifa/androidkaifa/2015/1012/3572.htmljava

相關文章
相關標籤/搜索