Rxjava

Rxjava 源于ReactiveX(Reactive Extensions),Rx是一個變成模型,目標是提供一致的編程接口,幫助開發者方便的處理異步數據流,許多流行的變成語言都有Rx庫。Rx擴展了觀察者模式,用于支持數據和事件序列,添加了一些操作符,他人你可以聲明式的組合這些序列,而無需關注底層的實現(線程、同步、線程安全、并發)。

Rxjava優勢就是使得代碼更簡潔,而且隨著程序邏輯變得越來越復雜,它依然能夠保持簡潔。

擴展的觀察者

Observable(被觀察者)、Observer(觀察者)、subscribe(訂閱),Observable和Observer通過subscribe方法實現訂閱關系。Observable在需要的時候發出事件來通知Observer。

與傳統的觀察者模式不同,除了定義了普通的回調事件onNext(),還定義的兩個特殊的事件onCompleted()和onError()。

  • onCompleted:事件隊列完結,Rxjava把所有事件看做一個隊列,并規定,當不會再有新的onNext事件觸發時,需要觸發onCompleted
  • onError:事件隊列異常,在時間處理過程中出現異常時觸發onError,同時隊列終止,不允許再有事件發出
  • onCompleted和onError有且只有一個,并且是事件序列的最后一個
基本實現

創建Observer,定義事件觸發時的具體行為

Observer<String> observer = new Observer<String>() {
   @Override
   public void onNext(String s) {
       Log.d(tag, "Item: " + s);
   }

   @Override
   public void onCompleted() {
       Log.d(tag, "Completed!");
   }

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

RxJava 還內置了一個實現了 Observer 的抽象類:Subscriber,Subscriber 對 Observer 接口進行了一些擴展,但他們的基本使用方式是完全一樣的。
與Observer 的主要區別:

  1. onStart:這是Subscriber 新增的方法,會在subscribe里,事件還未發送前調用,它總是在subscribe所發生的線程被調用
    2、unsubscribe:這是Subscriber 新增的方法,用于取消訂閱,這個方法被調用后,Subscriber將不再接收事件。Observable 會持有 Subscriber 的引用,這個引用如果不能及時被釋放,將有內存泄露的風險。所以最好保持一個原則:要在不再使用的時候盡快在合適的地方(例如 onPause() onStop() 等方法中)調用 unsubscribe() 來解除引用關系,以避免內存泄露的發生。
Subscription clickSubscribe = RxView.clicks(findViewById(R.id.bt))
           .throttleFirst(1, TimeUnit.SECONDS)
           .doOnUnsubscribe(new Action0() {
               @Override
               public void call() {
                   Log.e(TAG, "clicks->doOnUnsubscribe");
               }
           })
           .subscribe(new Action1<Void>() {
               @Override
               public void call(Void aVoid) {
                   methd6();
               }
           });
   //維護相關的資源引用
   subscriptions.add(clickSubscribe);

@Override
protected void onDestroy() {
   for (Subscription s : subscriptions) {
       if (!s.isUnsubscribed()) {
           s.unsubscribe();
           Log.e(TAG, "onDestroy: 取消訂閱!");
       }
   }
   super.onDestroy();
}

創建Observable,定義被觀察者,決定什么時候出發事件以及觸發怎么樣的事件

Observable observable = Observable.create(new Observable.OnSubscribe<String>() {
    @Override
    public void call(Subscriber<? super String> subscriber) {
        subscriber.onNext("Hello");
        subscriber.onNext("Hi");
        subscriber.onNext("Aloha");
        subscriber.onCompleted();
    }
});

創建Observable的操作符

  • create(OnSubscribe)
Observable observable = Observable.create(new Observable.OnSubscribe<String>() {
    @Override
    public void call(Subscriber<? super String> subscriber) {
        subscriber.onNext("Hello");
        subscriber.onNext("Hi");
        subscriber.onNext("Aloha");
        subscriber.onCompleted();
    }
});
  • just(T...): 將傳入的參數依次發送出來。
Observable observable = Observable.just("Hello", "Hi", "Aloha");
// 將會依次調用:
// onNext("Hello");
// onNext("Hi");
// onNext("Aloha");
// onCompleted();
  • from(T[]) / from(Iterable<? extends T>) : 將傳入的數組或 Iterable 拆分成具體對象后,依次發送出來。
String[] words = {"Hello", "Hi", "Aloha"};
Observable observable = Observable.from(words);
// 將會依次調用:
// onNext("Hello");
// onNext("Hi");
// onNext("Aloha");
// onCompleted();
  • empty 創建一個什么都不做直接通知完成的Observable
  • error 創建一個什么都不做直接通知錯誤的Observable
  • never 創建一個什么都不做的Observable
Observable observable1=Observable.empty();//直接調用onCompleted。
Observable observable2=Observable.error(new RuntimeException());//直接調用onError。這里可以自定義異常
Observable observable3=Observable.never();//啥都不做
  • timer 創建一個在給定的延時之后發射數據項為0的Observable<Long>
Observable.timer(1000,TimeUnit.MILLISECONDS)
            .subscribe(new Action1<Long>() {
                @Override
                public void call(Long aLong) {
                    Log.d("JG",aLong.toString()); // 0
                }
            });
  • interval 創建一個按照給定的時間間隔發射從0開始的整數序列的Observable<Long>
 Observable.interval(1, TimeUnit.SECONDS)
            .subscribe(new Action1<Long>() {
                @Override
                public void call(Long aLong) {
                     //每隔1秒發送數據項,從0開始計數
                     //0,1,2,3....
                }
            });
  • range 創建一個發射指定范圍的整數序列的Observable<Integer>
 Observable.range(2,5).subscribe(new Action1<Integer>() {
        @Override
        public void call(Integer integer) {
            Log.d("JG",integer.toString());// 2,3,4,5,6 從2開始發射5個數據
        }
    });
  • defer 只有當訂閱者訂閱才創建Observable,為每個訂閱創建一個新的Observable。內部通過OnSubscribeDefer在訂閱時調用Func0創建Observable。
 Observable.defer(new Func0<Observable<String>>() {
        @Override
        public Observable<String> call() {
            return Observable.just("hello");
        }
    }).subscribe(new Action1<String>() {
        @Override
        public void call(String s) {
            Log.d("JG",s);
        }
    });

合并操作符

  • concat: 按順序連接多個Observables。需要注意的是Observable.concat(a,b)等價于a.concatWith(b)。
Observable<Integer> observable1=Observable.just(1,2,3,4);
    Observable<Integer>  observable2=Observable.just(4,5,6);

    Observable.concat(observable1,observable2)
            .subscribe(item->Log.d("JG",item.toString()));//1,2,3,4,4,5,6
  • startWith: 在數據序列的開頭增加一項數據。startWith的內部也是調用了concat
Observable.just(1,2,3,4,5)
            .startWith(6,7,8)
    .subscribe(item->Log.d("JG",item.toString()));//6,7,8,1,2,3,4,5
  • merge 將多個Observable合并為一個。不同于concat,merge不是按照添加順序連接,而是按照時間線來連接。其中mergeDelayError將異常延遲到其它沒有錯誤的Observable發送完畢后才發射。而merge則是一遇到異常將停止發射數據,發送onError通知。
  • zip: 使用一個函數組合多個Observable發射的數據集合,然后再發射這個結果。如果多個Observable發射的數據量不一樣,則以最少的Observable為標準進行壓合。內部通過OperatorZip進行壓合。
Observable<Integer>  observable1=Observable.just(1,2,3,4);
Observable<Integer>  observable2=Observable.just(4,5,6);

Observable.zip(observable1, observable2, new Func2<Integer, Integer, String>() {
        @Override
        public String call(Integer item1, Integer item2) {
            return item1+"and"+item2;
        }
    })
    .subscribe(item->Log.d("JG",item)); //1and4,2and5,3and6
  • combineLatest 當兩個Observables中的任何一個發射了一個數據時,通過一個指定的函數組合每個Observable發射的最新數據(一共兩個數據),然后發射這個函數的結果。類似于zip,但是,不同的是zip只有在每個Observable都發射了數據才工作,而combineLatest任何一個發射了數據都可以工作,每次與另一個Observable最近的數據壓合。

過濾操作

  • filter 過濾數據。內部通過OnSubscribeFilter過濾數據。
Observable.just(3,4,5,6)
            .filter(new Func1<Integer, Boolean>() {
                @Override
                public Boolean call(Integer integer) {
                    return integer>4;
                }
            })
    .subscribe(item->Log.d("JG",item.toString())); //5,6 

還有ofType、take、takeLast、throttleFirst、timeout等

條件/布爾操作

  • all 判斷所有的數據項是否滿足某個條件,內部通過OperatorAll實現。
 Observable.just(2,3,4,5)
            .all(new Func1<Integer, Boolean>() {
                @Override
                public Boolean call(Integer integer) {
                    return integer>3;
                }
            })
    .subscribe(new Action1<Boolean>() {
        @Override
        public void call(Boolean aBoolean) {
            Log.d("JG",aBoolean.toString()); //false
        }
    })
    ;

還有exists、contains、isEmpty等

聚合操作

  • reduce: 對序列使用reduce()函數并發射最終的結果,內部使用OnSubscribeReduce實現。
 Observable.just(2,3,4,5)
            .reduce(new Func2<Integer, Integer, Integer>() {
                @Override
                public Integer call(Integer sum, Integer item) {
                    return sum+item;
                }
            })
            .subscribe(integer -> Log.d("JG",integer.toString()));//14

還有collect、count/countLong

轉換操作

  • toList 收集原始Observable發射的所有數據到一個列表,然后返回這個列表
 Observable.just(2,3,4,5)
            .toList()
            .subscribe(new Action1<List<Integer>>() {
                @Override
                public void call(List<Integer> integers) {

                }
            });

還有toSortedList、toMap、toMultiMap

變換操作

  • map 對Observable發射的每一項數據都應用一個函數來變換。
Observable.just(6,2,3,4,5)
            .map(integer -> "item:"+integer)
            .subscribe(s -> Log.d("JG",s));//item:6,item:2....

還有cast、flatMap、flatMapIterable、concatMap、switchMap等

錯誤處理/重試機制

  • onErrorResumeNext 當原始Observable在遇到錯誤時,使用備用Observable。
 Observable.just(1,"2",3)
    .cast(Integer.class)
    .onErrorResumeNext(Observable.just(1,2,3))
    .subscribe(integer -> Log.d("JG",integer.toString())) //1,2,3
    ;
  • onExceptionResumeNext 當原始Observable在遇到異常時,使用備用的Observable。與onErrorResumeNext類似,區別在于onErrorResumeNext可以處理所有的錯誤,onExceptionResumeNext只能處理異常。
  • onErrorReturn 當原始Observable在遇到錯誤時發射一個特定的數據。
Observable.just(1,"2",3)
            .cast(Integer.class)
            .onErrorReturn(new Func1<Throwable, Integer>() {
                @Override
                public Integer call(Throwable throwable) {
                    return 4;
                }
            }).subscribe(new Action1<Integer>() {
        @Override
        public void call(Integer integer) {
            Log.d("JG",integer.toString());1,4
        }
    });
  • retry: 當原始Observable在遇到錯誤時進行重試。
Observable.just(1,"2",3)
    .cast(Integer.class)
    .retry(3)
    .subscribe(integer -> Log.d("JG",integer.toString()),throwable -> Log.d("JG","onError"))
    ;//1,1,1,1,onError
  • retryWhen 當原始Observable在遇到錯誤,將錯誤傳遞給另一個Observable來決定是否要重新訂閱這個Observable,內部調用的是retry。
Observable.just(1,"2",3)
    .cast(Integer.class)
    .retryWhen(new Func1<Observable<? extends Throwable>, Observable<Long>>() {
        @Override
        public Observable<Long> call(Observable<? extends Throwable> observable) {
            return Observable.timer(1, TimeUnit.SECONDS);
        }
    })
    .subscribe(integer -> Log.d("JG",integer.toString()),throwable -> Log.d("JG","onError"));
    //1,1

還有一些操作符具體還是看RxJava操作符大全這個文章吧

線程控制

在不指定線程的情況下, RxJava 遵循的是線程不變的原則,即:在哪個線程調用 subscribe(),就在哪個線程生產事件;在哪個線程生產事件,就在哪個線程消費事件。如果需要切換線程,就需要用到 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。
  • 另外, Android 還有一個專用的 AndroidSchedulers.mainThread(),它指定的操作將在 Android 主線程運行。

使用 subscribeOn() 和 observeOn() 兩個方法來對線程進行控制

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

observeOn() 指定的是 Subscriber 的線程,而這個 Subscriber 并不是(嚴格說應該為『不一定是』,但這里不妨理解為『不是』)subscribe() 參數中的 Subscriber ,而是 observeOn() 執行時的當前 Observable 所對應的 Subscriber ,即它的直接下級 Subscriber 。換句話說,observeOn() 指定的是它之后的操作所在的線程。因此如果有多次切換線程的需求,只要在每個想要切換線程的位置調用一次 observeOn() 即可。

Observable.just(1, 2, 3, 4) // IO 線程,由 subscribeOn() 指定
    .subscribeOn(Schedulers.io())
    .observeOn(Schedulers.newThread())
    .map(mapOperator) // 新線程,由 observeOn() 指定
    .observeOn(Schedulers.io())
    .map(mapOperator2) // IO 線程,由 observeOn() 指定
    .observeOn(AndroidSchedulers.mainThread) 
    .subscribe(subscriber);  // Android 主線程,由 observeOn() 指定

subscribeOn() 的位置放在哪里都可以,但它是只能調用一次的。

doOnSubscribe()它和 Subscriber.onStart() 同樣是在 subscribe() 調用后而且在事件發送前執行,但區別在于它可以指定線程。默認情況下, doOnSubscribe() 執行在 subscribe() 發生的線程;而如果在 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);
相關資料

ReactiveX 的理念和特點
給 Android 開發者的 RxJava 詳解
RxJava操作符大全

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容