前言
RxJava以及RxAndroid(https://github.com/ReactiveX/RxAndroid)已經火了一段時間,這裡簡單的介紹一下它們。RxJava 在 GitHub 首頁上的自我介紹是 "a library for composing asynchronous and event-based programs using observable sequences for the Java VM"(一個在 Java VM 上使用可觀測的序列來組成非同步、基於事件的程式的庫)。實際上,它已經變成了一個專為 Android 而生的響應式第三方庫,主要是因為它是第一個全方位可用於 Java 支援的響應式第三方庫。RxJava 2 保留了我們需要在 Android 上支援的所有 Java 版本。關鍵字:響應式編程、非同步
歸結起來,它由三個主要的部分組成:
1.用於表示資料來源的一組類
2.用於偵聽資料來源的一組類
3.用於修改與合并資料的一組方法
當您開始偵聽資料來源的時候,它將開始或者停止執行某些操作。您可以將其想象為一種網路請求,除非您開始對網路回應進行偵聽,否則的話這個網路請求將永遠不會觸發。並且如果您在資料來源任務完成之前取消了對資料來源的訂閱,那麼它很可能會取消這個網路請求。
這些操作可以是同步的,也可以是非同步,因此您可以構造出一個類似網路請求的操作,它會在某個代碼塊當中運行,但是卻是運行在後台線程之上的。或者,它也可以是完全非同步,就像我們在 Android 中彈出 Activity 或者單擊 UI 當中的某個組件,這些都可以被視為非同步作業。
通常情況下,一個網路請求只會產生一條回應,但是只要您的 UI 還存在於那裡,即便您只訂閱了一個按鈕,您會發現,按鈕的單擊事件流卻可能是無限的。此外,它們所產生的回應也可能是空的,因此這種類型的資料來源實際上只有兩種功能:成功或者失敗,它不會產生任何的資料。您可以將其視為類似寫入資料庫或者寫入檔案的操作。它實際上並不會返回相關的回應或者資料;它要麼成功完成、要麼失敗。這種完成、失敗的回應程式面是由 RxJava 當中的資料來源,結合那些所謂「終端事件 (terminal event)」而構建的。這類似於那些可以正常返回、也可以拋出異常的方法。
這種響應也有可能永遠不會終止。讓我們回到之前的按鈕點擊操作樣本來,如果我們將按鈕點擊事件構建為資料來源,那麼只要您的這個 UI 還存在,那麼這個響應永遠都不會結束。只有當 UI 消失,並且您取消了該按鈕點擊事件的訂閱之後,才可能會結束。在此之前,它將永遠不會進入到完成狀態。
這一切相當於實現了傳統的觀察者模式。我們有某些可以產生資料的組件,然後我們只想知道它們所產生的資料是什麼,因此我們所要做的僅僅只是觀察而已。所以我們可以添加一個監聽器,當事件發生的時候就收到相應的通知。
基本使用
前面囉嗦了一大堆,感覺好像沒什麼卵用。直接進入正題,對於程式猿來說,代碼比文字更容易理解吧。
build.gradle 中請依賴,
compile 'io.reactivex.rxjava2:rxandroid:2.0.1'// Because RxAndroid releases are few and far between, it is recommended you also// explicitly depend on RxJava's latest version for bug fixes and new features.compile 'io.reactivex.rxjava2:rxjava:2.0.1'
private void createFlowable(final String str) { Flowable<String> flowable = Flowable.create(new FlowableOnSubscribe<String>() { @Override public void subscribe(FlowableEmitter<String> e) throws Exception { //onNext方法就是發射一個任務:比如本例子中的開燈動作 e.onNext(str); //事件完成後調用 e.onComplete(); } }, BackpressureStrategy.BUFFER); //支援背壓,不丟棄資料的處理方式 Subscriber<String> subscriber = new Subscriber<String>() { @Override public void onSubscribe(Subscription s) { Log.d(TAG, "---onSubscribe---"); //必須設定可請求的次數,否則不會執行onNext和onComplete方法 s.request(Long.MAX_VALUE); } @Override public void onNext(String s) { Log.d(TAG, "---onNext-->" + s); Toast.makeText(mContext, s, Toast.LENGTH_SHORT).show(); } @Override public void onError(Throwable t) { Log.e(TAG,"---onError-->",t); } @Override public void onComplete() { Log.d(TAG, "---onComplete-->the light is on"); } }; //subscribe:發射源執行這個事件 flowable.subscribe(subscriber); }
createFlowable("turn the light on!");執行
04-20 13:43:08.904 12293-12293/org.jan.rxandroiddemo D/SimpleFunc1Activity: ---onSubscribe---04-20 13:43:08.904 12293-12293/org.jan.rxandroiddemo D/SimpleFunc1Activity: ---onNext-->turn the light on!04-20 13:43:08.944 12293-12293/org.jan.rxandroiddemo D/SimpleFunc1Activity: ---onComplete-->the light is on
Flowable大意是流動性的,我們可以把它想象成某種事件隊列的發射源。 建立一個Flowable發射源,假設程式猿加班回家開燈這樣的一件事來說,開燈然後燈亮,開燈的動作組合由Flowable來安排執行(subscribe)。 Subscriber 可以想象成一個事件的處理和響應接收器。開燈動作之後,如電流通過燈泡的物理反應,就是在這個對象裡的方法裡(onNext)處理。
是不是覺得寫法有些複雜啊,Rxjava中有個just的方法,會自動根據你的輸入參數自行調用onNext方法哦
來一波代碼示意
private void createSimpleFlowable(String params) { Flowable.just(params).subscribe(new Consumer<String>() { @Override public void accept(String s) throws Exception { Log.i(TAG,"---accept-->"+s); Toast.makeText(mContext, s, Toast.LENGTH_SHORT).show(); } }); } 調用一下 createSimpleFlowable("turn the light off!");
04-20 14:15:37.864 18583-18583/org.jan.rxandroiddemo I/SimpleFunc1Activity: ---accept-->turn the light off!
變換入門
哈哈哈,我們還可以在輸入到輸出的過程中對資料做變換操作,什麼意思。上代碼。
Flowable.just("hello! RxJava2") .subscribe(new Consumer<String>() { @Override public void accept(String s) throws Exception { Log.i(TAG,"Android-jan:"+s); } });
04-20 14:37:07.634 15173-15173/org.jan.rxandroiddemo I/SimpleFunc1Activity: Android-jan:hello! RxJava2
操作符
1.map轉換,map函數會返回一個被轉換後的Flowable對象哦
private void map(String str) { Flowable.just(str).map(new Function<String, String>() { @Override public String apply(String s) throws Exception { //這兒我們做點小動作 return s+"下午3點"; } }).subscribe(new Consumer<String>() { @Override public void accept(String s) throws Exception { Log.i(TAG,"---accept-->"+s); Toast.makeText(mContext, s, Toast.LENGTH_SHORT).show(); } }); }
調用我的方法:map("2017年4月20日"); 看看列印了什麼。其實你心中早有結果。
04-20 15:44:48.834 25851-25851/org.jan.rxandroiddemo I/SimpleFunc1Activity: ---accept-->2017年4月20日下午3點
再來一波,看看能不能雙map執行,
/** * 把輸入參數str的hashcode轉換成String 並且列印出來 * @param str */ private void map2(String str) { Flowable.just(str).map(new Function<String, Integer>() { @Override public Integer apply(String s) throws Exception { return s.hashCode(); } }).map(new Function<Integer, String>() { @Override public String apply(Integer integer) throws Exception { return integer.toString(); } }).subscribe(new Consumer<String>() { @Override public void accept(String s) throws Exception { Log.i(TAG,s); Toast.makeText(mContext, s, Toast.LENGTH_SHORT).show(); } }); }沒錯,列印結果是正確的。
2.fromIterable方法,如果我現在手裡有一組列表,我要通過Flowable把它射出去 ,我來教你
List<Integer> list = new ArrayList<>(); list.add(10); list.add(15); list.add(20); list.add(256); list.add(1000); Flowable.fromIterable(list).subscribe(new Consumer<Integer>() { @Override public void accept(Integer integer) throws Exception { Log.i(TAG,"---from->"+integer); } });
列印結果:
04-20 16:38:16.404 24914-24914/org.jan.rxandroiddemo I/SimpleFunc1Activity: ---from->1004-20 16:38:16.404 24914-24914/org.jan.rxandroiddemo I/SimpleFunc1Activity: ---from->1504-20 16:38:16.404 24914-24914/org.jan.rxandroiddemo I/SimpleFunc1Activity: ---from->2004-20 16:38:16.404 24914-24914/org.jan.rxandroiddemo I/SimpleFunc1Activity: ---from->25604-20 16:38:16.404 24914-24914/org.jan.rxandroiddemo I/SimpleFunc1Activity: ---from->1000
3.flatMap操作符,感覺跟map有點像,實際上比map厲害了,主要用來破除嵌套結構。先不用著急,咱們可以先確定的事是 它可以把一個 Flowable 轉換成另一個 Flowable。
List<Integer> list = new ArrayList<>(); list.add(10); list.add(15); list.add(20); list.add(256); list.add(1000); Flowable.just(list).flatMap(new Function<List<Integer>, Publisher<String>>() { @Override public Publisher<String> apply(List<Integer> integers) throws Exception { //這段代碼意思不重要,重要的是,它能幫你轉換你的輸入參數,並返回一個Publisher發射源:Flowable List<String> strs = new ArrayList<String>(); for(Integer integer:integers){ strs.add(String.valueOf(integer)); } return Flowable.fromIterable(strs); } }).subscribe(new DefaultSubscriber<String>() { @Override public void onNext(String s) { //這裡接收的不是Integer類型了,已經處理成String類型 Log.i(TAG,"---onNext-->"+s); } @Override public void onError(Throwable t) { Log.e(TAG,"---onError-->",t); } @Override public void onComplete() { Log.i(TAG,"---onComplete---"); } });列印結果:
04-20 17:28:39.044 3101-3101/org.jan.rxandroiddemo I/SimpleFunc1Activity: ---onNext-->1004-20 17:28:39.044 3101-3101/org.jan.rxandroiddemo I/SimpleFunc1Activity: ---onNext-->1504-20 17:28:39.044 3101-3101/org.jan.rxandroiddemo I/SimpleFunc1Activity: ---onNext-->2004-20 17:28:39.044 3101-3101/org.jan.rxandroiddemo I/SimpleFunc1Activity: ---onNext-->25604-20 17:28:39.044 3101-3101/org.jan.rxandroiddemo I/SimpleFunc1Activity: ---onNext-->100004-20 17:28:39.044 3101-3101/org.jan.rxandroiddemo I/SimpleFunc1Activity: ---onComplete---
如果你沒完全理解的話,請轉 關於RxJava的from()和 flatMap()方法
4.filter操作符,過濾的意思,假設我們要過濾一組數組,來個條件吧
Integer[] array = {1,2,3,5,6,4,0}; Flowable.fromArray(array).filter(new Predicate<Integer>() { @Override public boolean test(Integer integer) throws Exception { //把數組中大於4的元素過濾出來 return integer.intValue()>4; } }).subscribe(new Consumer<Integer>() { @Override public void accept(Integer integer) throws Exception { Log.i(TAG,"filter->integer="+integer); } });列印結果:
04-20 17:42:33.764 3101-3101/org.jan.rxandroiddemo I/SimpleFunc1Activity: filter->integer=504-20 17:42:33.764 3101-3101/org.jan.rxandroiddemo I/SimpleFunc1Activity: filter->integer=6
5.take操作符,限制發射源發射的數量,take(3)意思就是只能發射3次元素
Integer[] array = {1,2,7,5,6,4,0}; Flowable.fromArray(array).take(3).subscribe(new Consumer<Integer>() { @Override public void accept(Integer integer) throws Exception { Log.i(TAG,"take->integer="+integer); } });列印結果:
04-20 17:49:54.784 22016-22016/org.jan.rxandroiddemo I/SimpleFunc1Activity: take->integer=104-20 17:49:54.784 22016-22016/org.jan.rxandroiddemo I/SimpleFunc1Activity: take->integer=204-20 17:49:54.784 22016-22016/org.jan.rxandroiddemo I/SimpleFunc1Activity: take->integer=7
6.doOnNext方法:如果我們想在訂閱者接收到資料前幹點事情,比如記錄日誌。
Integer[] array = {1,2,3,5,6,4,0}; Flowable.fromArray(array).doOnNext(new Consumer<Integer>() { @Override public void accept(Integer integer) throws Exception { //在訂閱之前可以進行日誌記錄 Log.i(TAG,"doOnNext->integer="+integer); } }).subscribe(new Consumer<Integer>() { @Override public void accept(Integer integer) throws Exception { Log.i(TAG,"subscribe->integer="+integer); } });列印結果:
04-20 17:51:57.324 22016-22016/org.jan.rxandroiddemo I/SimpleFunc1Activity: doOnNext->integer=104-20 17:51:57.324 22016-22016/org.jan.rxandroiddemo I/SimpleFunc1Activity: subscribe->integer=104-20 17:51:57.324 22016-22016/org.jan.rxandroiddemo I/SimpleFunc1Activity: doOnNext->integer=204-20 17:51:57.324 22016-22016/org.jan.rxandroiddemo I/SimpleFunc1Activity: subscribe->integer=204-20 17:51:57.324 22016-22016/org.jan.rxandroiddemo I/SimpleFunc1Activity: doOnNext->integer=304-20 17:51:57.324 22016-22016/org.jan.rxandroiddemo I/SimpleFunc1Activity: subscribe->integer=304-20 17:51:57.324 22016-22016/org.jan.rxandroiddemo I/SimpleFunc1Activity: doOnNext->integer=504-20 17:51:57.324 22016-22016/org.jan.rxandroiddemo I/SimpleFunc1Activity: subscribe->integer=504-20 17:51:57.324 22016-22016/org.jan.rxandroiddemo I/SimpleFunc1Activity: doOnNext->integer=604-20 17:51:57.324 22016-22016/org.jan.rxandroiddemo I/SimpleFunc1Activity: subscribe->integer=604-20 17:51:57.324 22016-22016/org.jan.rxandroiddemo I/SimpleFunc1Activity: doOnNext->integer=404-20 17:51:57.324 22016-22016/org.jan.rxandroiddemo I/SimpleFunc1Activity: subscribe->integer=404-20 17:51:57.324 22016-22016/org.jan.rxandroiddemo I/SimpleFunc1Activity: doOnNext->integer=004-20 17:51:57.324 22016-22016/org.jan.rxandroiddemo I/SimpleFunc1Activity: subscribe->integer=0
今天就先寫這麼些吧,反正就是基礎使用,各位看官先消化消化吧。