前言 RxAndroid是RxJava在Android上的一個擴展,大牛JakeWharton的項目。聽說和Retorfit、OkHttp組合起來使用,效果不是通常的好。並且用它彷佛能夠徹底替代eventBus和OTTO,這麼牛的東西固然要研究研究了 ,看看它到底有多厲害。 正文 相關資源 RxJava的GitHub地址:https://github.com/ReactiveX/RxJava RxAndroid的GitHub地址:https://github.com/ReactiveX/RxAndroid 中文文檔:https://mcxiaoke.gitbooks.io/rxdocs/content/ 一篇寫的比較好的入門RxJava的文章的地址:http://gank.io/post/560e15be2dca930e00da1083 1.RxJava是幹嗎的 Rx(Reactive Extensions)是一個庫,用來處理事件和異步任務,在不少語言上都有實現,RxJava是Rx在Java上的實現。簡單來講,RxJava就是處理異步的一個庫,最基本是基於觀察者模式來實現的。經過Obserable和Observer的機制,實現所謂響應式的編程體驗。 Android的童鞋都知道,處理異步事件,現有的AsyncTask、Handler,不錯的第三方事件總線EventBus、OTTO等等均可以處理。而且大部分童鞋應該都很熟練了。並且經我目前的學習來看,RxJava這個庫,上手確實有門檻,不是拿來就能用。可是做爲一個猿,那些可能出現的優秀的框架技術,及時的跟進和學習是必要的,從中汲取養分才能幫助本身成長。何況有童鞋已經表示,它徹底能夠替代EventBus和OTTO,來看看吧。 2.RxJava的優點 最歸納的兩個字:簡潔。並且當業務越繁瑣越複雜時這一點就越顯出優點——它可以保持簡潔。 簡單的demo看不出來,真正投入項目使用了應該就有體會了。它提供的各類功能強悍的操做符真的很強大。 3.基本使用流程 這裏只介紹Android Studio的接入方式,若是你還在用Eclipse的話,我建議你換了。 配置buile.gradle:(如下爲當前最新版本,若有更新請到上述GitHub連接查看更新) dependencies { compile 'io.reactivex:rxandroid:1.2.1' compile 'io.reactivex:rxjava:1.1.6' } 配置完以後就可使用RxJava的API了。介紹兩個個關鍵的類: (1)Observable (2)Subscriber 即:被觀察者(Observable)和觀察者(Subscriber),其實我以爲叫發佈者和訂閱者更好理解一些,但你們都叫被觀察者和觀察者。 主幹的使用過程就是1.建立被觀察者。2.建立觀察者。3.將兩者創建聯繫。完畢。而後被觀察中發出信息觸發觀察者的動做,執行相應的方法,就這樣。你先別急着吐槽它很平庸。它的強大在於這個過程當中提供的各類操做變換的技巧會讓你能夠簡潔的處理至關繁瑣的代碼邏輯。 先看一個簡單的demo: //建立一個被觀察者(發佈者) Observable observable = Observable.create(new Observable.OnSubscribe<Integer>() { @Override public void call(Subscriber<? super Integer> subscriber) { subscriber.onNext(1001); subscriber.onNext(1002); subscriber.onNext(1003); subscriber.onCompleted(); } }); //建立一個觀察者 Subscriber<Integer> subscriber = new Subscriber<Integer>() { @Override public void onCompleted() { Log.d(TAG, "onCompleted.. "); } @Override public void onError(Throwable e) { Log.d(TAG, "subscriber onError.. " + e.getMessage()); } @Override public void onNext(Integer integer) { Log.d(TAG, "onNext.. integer:" + integer); } }; //註冊觀察者(這個方法名看起來有點怪,還不如寫成regisiterSubscriber(..)或者乾脆addSubscriber(..)) //註冊後就會開始調用call()中的觀察者執行的方法 onNext() onCompleted()等 observable.subscribe(subscriber); 上面的例子中,當Observable發射數據時,會依次調用Subscriber的onNext()方法,將發射的數據做爲參數傳給onNext(),若是出錯,則會調用Subscriber的onError()方法,完成全部數據發射後,調用onCompleted()方法,整個過程完畢。 可是,subcribe()方法默認在當前線程被調用。因此,這樣使用的話,被觀察者和觀察者的全部的動做都是在同一個線程完成的,沒卵用… 可是固然確定不會就這個程度了,RxJava有兩個方法能夠很方便的指定觀察者和被觀察者代碼運行的線程,RxAndroid還有一個擴展,能夠指定在UI線程運行。你懂的! 以下: //設置觀察者和發佈者代碼所要運行的線程後註冊觀察者 observable.subscribeOn(Schedulers.immediate())//在當前線程執行subscribe()方法 .observeOn(AndroidSchedulers.mainThread())//在UI線程執行觀察者的方法 .subscribe(subscriber); 經過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 主線程運行。 4.Observable建立方式 以上介紹了主幹使用流程,從這裏咱們往細一點再看。前文說了,RxJava的強大之處在於它的各類操做符。在建立Observable對象的方式上,一樣有不少方便的操做符的實現,上面是經過Observable.create()方法建立的observable對象,這裏介紹其餘幾個經常使用的方法。 經過from建立Observable: //Teacher爲一個數據Bean,包含姓名,年齡,住址三個字段 List<Teacher> teachers = new ArrayList<>(); for (int i = 0; i < 4; i++) { teachers.add(new Teacher("name" + i, i, "place" + i)); } //from方法支持繼承了Interable接口的參數,因此經常使用的數據結構(Map、List..)均可以轉換 Observable fromObservale = Observable.from(teachers); fromObservale.subscribe(new Subscriber<Teacher>() { @Override public void onCompleted() { Log.i(TAG, "from(teachers) onCompleted"); } @Override public void onError(Throwable e) { Log.e(TAG, "from(teachers) " + e.getMessage()); } @Override public void onNext(Teacher teacher) { //依次接收到teachers中的對象 Log.d(TAG, "from(teachers) onNext:" + teacher.toString()); } }); 用from方法建立Observable,能夠傳入一個數組,或者一個繼承了Iterable的類的對象做爲參數,也就是說,java中經常使用的數據結構如List、Map等均可以直接做爲參數傳入from()方法用以構建Observable。這樣,當Observable發射數據時,它將會依次把序列中的元素依次發射出來。 經過just建立Observable: //Just相似於From,可是From會將數組或Iterable的元素具取出而後逐個發射,而Just只是簡單的原樣發射,將數組或Iterable當作單個數據。 //Just接受一至九個參數,返回一個按參數列表順序發射這些數據的Observable Observable justObservable = Observable.just(1, "someThing", false, 3.256f, new Teacher("Jhon", 25, "NewYork")); justObservable.subscribe(new Subscriber() { @Override public void onCompleted() { Log.i(TAG, "just(...) onCompleted"); } @Override public void onError(Throwable e) { Log.d(TAG, "just(...) onError:" + e.getMessage()); } @Override public void onNext(Object o) { Log.d(TAG, "just(...) onNext:" + o.toString()); } }); just直接接收object做爲參數,原樣發射出來,也是很是方便的。 經過timer建立Observable: //timer()建立一個Observable,它在一個給定的延遲後發射一個特殊的值 設定執行方法在UI線程執行 //延時兩秒後發射值 //實測 延時2s後發送了一個0 Observable timerObservable = Observable.timer(2, TimeUnit.SECONDS, AndroidSchedulers.mainThread()); timerObservable.subscribe( new Subscriber() { @Override public void onCompleted() { Log.i(TAG, "timer(...) onCompleted"); refreshStr("timer(...) onCompleted\n"); } @Override public void onError(Throwable e) { Log.e(TAG, "timer(...) onError:" + e.getMessage()); refreshStr("timer(...) onError:" + e.getMessage()); } @Override public void onNext(Object o) { Log.d(TAG, "timer(...) onNext:" + o.toString()); refreshStr("timerObservable 延時兩秒觸發 發送值:" + o.toString()); } } ); timer有定時的做用,延時發送一個值0。 經過range建立Observable(這裏疊加使用一個repeat方法): //range 發射從n到m的整數序列 能夠指定Scheduler設置執行方法運行的線程 //repeat方法能夠指定重複觸發的次數 Observable rangeObservable = Observable.range(3, 7).repeat(2); rangeObservable.subscribe( //在不寫觀察者的狀況下,可使用Action1和Action0這兩個接口來實現不完整定義的回調; 參見:ActionSubscriber //Action1<T>能夠代替實現onNext(); Action1<Throwable>能夠代替實現onError(); Action0能夠代替實現onConplete() new Action1() { @Override public void call(Object o) { Log.e(TAG, "range(3, 7).repeat(2) onNext:"+o.toString()); } }, new Action1<Throwable>() { @Override public void call(Throwable throwable) { Log.e(TAG, "range(3, 7).repeat(2) "+throwable.getMessage()); } }, new Action0() { @Override public void call() { Log.i(TAG, "range(3, 7).repeat(2) onCompleted"); } }); range發射從n到m的整數序列,repeat能夠指定重複次數,以上發射的次序爲:3,4,5,6,7,3,4,5,6,7。這裏用到的Action0和Action1是兩個能夠替代Subscriber的接口,具體能夠參見相關文檔和源碼實現,這裏不深刻介紹。 其餘還有Interval、Defer、Start等方法就不一一介紹了,本文主要是幫助初次接觸的童鞋入門,RxJava的操做符很是豐富,這裏很難一一說明,更多的內容要還須要你們本身去熟悉和探究。 5.變換操做 除了多樣的Observable建立方式,RxJava還有一個神奇的操做就是變換。經過本身定義的方法,你能夠將輸入的值變換成另外一種類型再輸出(好比輸入url,輸出bitmap),單一變換、批量變換、甚至實現雙重變換,嵌套兩重異步操做!而且代碼格式一如既往的乾淨平整。是否是很牛? 使用map()方法作轉換: Runnable run = new Runnable() { @Override public void run() { //將文件路徑轉換爲bitmap發出 觀察者直接收到bitmap進行處理 Observable observable = Observable.just(imgFilePath); observable.map(new Func1<String, Bitmap>() { @Override public Bitmap call(String imgFilePath) { return getBitmapFromAssets(imgFilePath); } }).subscribeOn(Schedulers.immediate())//當前線程(子線程)發佈 .observeOn(AndroidSchedulers.mainThread())//UI線程執行(更新圖片) .subscribe(new Subscriber<Bitmap>() { @Override public void onCompleted() { Log.i(TAG, "observable.map(..) onCompleted"); } @Override public void onError(Throwable e) { Log.i(TAG, "observable.map(..) onError" + e.getMessage()); } @Override public void onNext(Bitmap bitmap) { //顯示圖片 iv.setImageBitmap(bitmap); } }); } }; new Thread(run).start(); map()方法是最基本的變換操做,這裏只變換了一個數據,將文件路徑解析爲Bitmap顯示出來。你固然也能夠多傳入幾個參數或者用from操做符傳入一個數組或者集合等,批量操做,而且同時指定代碼運行的線程。並且這些全部的操做均可以在一條鏈式代碼中所有完成,易讀易維護。你是否是已經有一點體會到它的威力了? flatMap()實現雙重變換 flatMap()將一個發射數據的Observable變換爲多個Observables,而後將它們發射的數據合併後放進一個單獨的Observable。即:第一次轉換時,它依次將輸入的數據轉換成一個Observable,而後將這些Observable發射的數據集中到一個Observable裏依次發射出來。以爲莫名其妙?來看一個實際例子: Subscriber subscriber = new Subscriber<Integer>() { @Override public void onCompleted() { Log.i(TAG,"Observable.just(array1,array2).flatMap onCompleted\n\n"); } @Override public void onError(Throwable e) { Log.e(TAG,"Observable.just(array1,array2).flatMap onError "+e.getMessage()); } @Override public void onNext(Integer integer) { Log.d(TAG,"Observable.just(array1,array2).flatMap integer = "+integer); } }; //flatMap能夠實現一個雙重轉換,在它的回調方法中會返回一個observable對象,但它並不會直接發射這個對象 //而是將這個observable對象要發射的值 集中到一個新的observable對象中依次發射 //如本例,第一層Observable依次發射兩個數組,通過flatmap轉換以後,變成變成兩個依次發射數組元素的observable // 最後在subscriber中接收到的直接是整型數,等於將兩個數組"鋪開"了,直接發射整數,這就是大概地"flat"的含義吧 // flatMap方法能夠很靈活的使用,實現雙重變換,知足不少不一樣狀況下的需求,好比處理嵌套的異步代碼等,很是棒! Integer[] array1 = {1, 2, 3, 4}, array2 = {5, 6, 7, 8}; Observable.just(array1,array2).flatMap(new Func1<Integer[], Observable<?>>() { @Override public Observable<?> call(Integer[] ints) { Observable observable = Observable.from(ints); return observable; } }).subscribe(subscriber); 這裏flatMap()方法將最初傳入的兩個數組在第一次變換時,經過from操做符變換成兩個Observable,而後在將這兩個Observable發射的數據所有集中到一個新的Observable中集中發射,等於將兩個數組」鋪開」了,依次發射出來它們的元素。具體轉換的方法由你指定,使用的方式是比較靈活的。 好比有的商城類應用的需求:先要拿到某類別的一個產品列表,而後列表中有具體產品展現圖片的url,須要你拿到產品列表信息後依次去請求圖片,成功後更新到UI頁面上,使用flatMap,你確定知道怎麼寫了吧,是否是比CallBack跳來跳去的舒服一些? scan()變換 scan操做符對原始Observable發射的第一項數據應用一個函數,而後將那個函數的結果做爲本身的第一項數據發射。它將函數的結果同第二項數據一塊兒填充給這個函數來產生它本身的第二項數據。它持續進行這個過程來產生剩餘的數據序列。 當看到這裏的時候,我已經由衷的在感嘆,這些操做符實在太TM豐富了,而後對它的強大已經開始有所體會和感悟了。這種產生斐波那契數列的操做都給封裝進去了,並且函數由你自定義,你能用它作成什麼,可能在靈感到來以前你本身都想不到。 demo代碼: //scan 會將輸入的第一個元素看成參數作一個函數運算(函數由你實現,規定須要兩個參數,此時另外一個默認沒有),而後發射結果 // 同時,運算結果會被看成函數的與第二個參數與第二個元素再進行函數運算,完成後發射結果 // 而後將這個結果與第三個元素做爲函數的參數再次運算...直到最後一個元素 Observable.just(1, 2, 3, 4).scan(new Func2<Integer, Integer, Integer>() { @Override public Integer call(Integer integer, Integer integer2) { //integer是第一個元素或上一次計算的結果,integer2是下一輪運算中新的序列中元素 Log.d(TAG, "scan call integer:" + integer + " integer2:" + integer2); return integer + integer2; } }).subscribe(new Subscriber<Integer>() { @Override public void onCompleted() { Log.i(TAG, "Observable.just(1,2,3,4).scan onCompleted.."); initViewState(); } @Override public void onError(Throwable e) { Log.e(TAG, "Observable.just(1,2,3,4).scan onError " + e.getMessage()); } @Override public void onNext(Integer integer) { Log.d(TAG, "Observable.just(1,2,3,4).scan onNext().. integer = " + integer); /** * 第一次爲1,而後是3(1+2),6(3+3),10(6+4) */ } }); 註釋和上面的說明都很清晰了,就再也不贅述。一樣,關於轉換操做,也還有不少其餘的操做符,如wiindow() buffer() 等已實現的方法,具體參見文檔吧。 6.過濾、結合操做 在文檔的分類中,還有兩片基礎API是過濾和結合的操做符,例如:Filter、Skip、Take、Merage、Zip等等,原本打算一塊兒列舉的,可是想一想其實若是熟悉了上面的內容,這兩塊相關的API上手其實也很容易了。若是入門目的已經達到,再講這個顯得有點囉嗦。因此略去,若是之後有心得,在開篇另講那些操做符的使用,RxJava的知識,主要仍是要靠本身多熟悉,多研究。 尾聲 本文主要但願幫助初次接觸RxJava的童鞋入門,講的一些基礎知識,RxJava太大,內容太豐富,入門以後須要下的功夫也很多,但願你們都能day day up! 最後,如發現內容有誤,請斧正! 很是感謝!