intro
"森林里的一棵樹倒下來,如果周圍沒有人聽見,那么就等于說樹的倒下是寂靜無聲的."
隨著產(chǎn)品功能的增加,公司的業(yè)務(wù)代碼邏輯趨于復(fù)雜,閱讀難度也隨著提升,故想引入 Rxjava .先前對之只有簡單的了解,只知道其是響應(yīng)式編程.但響應(yīng)式編程又是什么呢?在計算機(jī)中,響應(yīng)式編程是一種面向數(shù)據(jù)流和變化傳播的編程范式.我的理解其實(shí)就是類似事件監(jiān)聽,"你去完成某項(xiàng)操作,完成了告訴我就行."也就是一種簡單的觀察者模式.在這其中,如果事件間有什么邏輯關(guān)系你可以在你的發(fā)送事件那里進(jìn)行處理,形成事件流.許許多多的類似操作就成了事件池.這樣,我們可以把所有的異步操作都扔到這個池中,當(dāng)然我們也只需在監(jiān)聽拿到這個事件池中發(fā)出的事件進(jìn)行處理即可.
以下是官網(wǎng)介紹:a library for composing asynchronous and event-based programs using observable sequences for the Java VM
RxJava就是一個實(shí)現(xiàn)異步操作的庫.請記住,異步異步異步,你引入這個庫到你項(xiàng)目中并在學(xué)習(xí)Rxjava過程中也請時刻牢記這個詞.
為什么響應(yīng)式和為什么Rxjava
完全同步操作編寫的應(yīng)用在實(shí)際項(xiàng)目中是不存在的,異步源操作存在使得我們編程的復(fù)雜度大大提升.各種異步源的操作是不穩(wěn)定的,我們不能假設(shè)其操作永遠(yuǎn)成功然后輸出我們需要的結(jié)果.反之需要記錄各種異步源操作的結(jié)果與狀態(tài),將之反應(yīng)到相應(yīng)屬性中或者是后續(xù)動作.例如,我們可以在每次異步調(diào)用后提供一個回調(diào)處理 Runnable 去進(jìn)行后續(xù)的響應(yīng)操作.也就是,"我操作成功了你拿我的結(jié)果去搞事情吧".這其實(shí)不是說得這么簡單,我們需要對可能發(fā)生的問題進(jìn)行處理,也就是"我操作搞砸了你之后應(yīng)怎么辦".
這都是對于異步操作的描述,而我們維護(hù)這些操作的狀態(tài).隨著多個異步調(diào)用的出現(xiàn),我們需要維護(hù)更多的狀態(tài)與屬性,或是一個異步操作是在另一個異步操作之后進(jìn)行調(diào)用的或是更為復(fù)雜邏輯.當(dāng)然,在Android中我們還需考慮其回調(diào)操作所在的線程,避免崩潰.許許多多的狀態(tài)維護(hù)與其他的線程操作間的協(xié)調(diào)處理會帶來極高的復(fù)雜度.試想,一個界面需要在幾個網(wǎng)絡(luò)請求完成后才顯示界面,這樣你需分別判斷維護(hù)各個請求成功與否的狀態(tài)等等問題.響應(yīng)式其實(shí)就是為了解決這個問題,為了讓我們能直接與異步源操作直接關(guān)聯(lián),通過訂閱關(guān)系,在你數(shù)據(jù)發(fā)生變更的時候我們才做出響應(yīng).當(dāng)然,這種響應(yīng)模型應(yīng)該要能處理多個異步源的請求,我們所編寫的代碼應(yīng)該位于模型與異步源的中間弦叶,作為狀態(tài)仲裁器 (state arbiter) 來使用场绿,而不用試圖去協(xié)調(diào)所有異步源的操作.這樣,我們終于可以把異步源操作連接在一起了,而不用去試圖管理所有的狀態(tài)和事件而去編寫混亂的代碼了.
這也就是我們需要 Rxjava 的原因所在.
RxJava2
RxJava由用于表示數(shù)據(jù)源的一組類,用于偵聽數(shù)據(jù)源的一組類,用于修改與合并數(shù)據(jù)的一組方法組成.
數(shù)據(jù)源可以分為有盡源和無盡源兩種.在無盡源的情況下,系統(tǒng)接收處理事件往往會爆掉內(nèi)存如果沒有對之進(jìn)行處理的話. RxJava2 表示提供事件源的過程提供了兩種類型: Flowable 和 Observable. 區(qū)別就是 Flowable 支持背壓,即我們上述所說的進(jìn)行處理,背壓控制方式,增大其事件源的事件池的大小,控制事件一次所能接收的數(shù)目等方法.以下是 RxJava給我們提供的接口方法:
BackpressureStrategy.BUFFER BackpressureStrategy.DROP BackpressureStrategy.LATEST / onBackpressureBuffer() onBackpressureDrop() onBackpressureLatest()
關(guān)于事件源的發(fā)出與接收是以發(fā)送方為主導(dǎo)的,我可以發(fā)送無數(shù)個,你也可以接收無數(shù)個.事件源發(fā)送完成了 onComplete 或是發(fā)生錯誤 onError, 下游接收方則會停止接收事件, 但之后如果事件源還有事件發(fā)送事件源則會繼續(xù)進(jìn)行他的工作而不管他的事件會不會被接收到.
事件源發(fā)出就是直接發(fā)出去的嗎?不是的.事件源通過onNext,just等接口方法發(fā)出去時,會在內(nèi)存中申請一個事件池的東西,我們可以這樣叫他, 我們接收的事件是再從里面拿出來的. 在 onSubscribe 中的 Disposable 對象上,我們可以通過 request 方法請求我們需要或是能處理的事件數(shù)目. 這也是處理背壓的一種方式了!
修改合并數(shù)據(jù)的一組方法,如 map, flatmap, zip 等, 切換線程的方法 observerOn, subscribeOn.注意的是不要把計算工作放在 Schedulers.io()中,避免創(chuàng)建不必要的線程,也不要把 I/O 操作置于 ?Schedulers.computation() 中浪費(fèi) CPU 資源. 多個 subscribeOn 對線程的指定其實(shí)只有第一個會有效用, 而 observerOn 則是對后續(xù)接收事件流所在線程的指定. 修改合并數(shù)據(jù)的一組方法和切換線程的操作原理都是通過 lift 方法對事件進(jìn)行"代理監(jiān)聽". 我是這樣理解的. 當(dāng)你需要切換線程時或是需要對接收發(fā)送的數(shù)據(jù)進(jìn)行處理, lift 先在另一線程或是進(jìn)行數(shù)據(jù)處理之后通知本身說我這邊的變換已經(jīng)完成了,你可以把你的事件發(fā)送到目標(biāo) Subscriber 了. 多次變換情況一樣.
必須記住要去管理返回的 Diaposable , 避免代碼在 Activity 消失之后還繼續(xù)運(yùn)行造成的內(nèi)存泄露!
最后,正襟危坐跑一下Learn RxJava By Examples是個不錯的選擇.
常用的方法:
創(chuàng)建操作符:create()桑谍、just()(并發(fā)酌呆,不超過10個)继谚、fromArray(T... items)奏路、fromCallable()阔蛉、fromFuture()(增加 cancel()等方法操作的Callable)弃舒、fromIterable(Iterable<? extends T> source)、defer()(被訂閱后才會創(chuàng)建)状原、timer()聋呢、iterval()(自增1的 timer)、intervalRange()颠区、range()削锰、rangeLong()、empty()&never()&error()
轉(zhuǎn)換操作符:map()(可轉(zhuǎn)換發(fā)送的數(shù)據(jù)類型)毕莱、flatMap()(整合加工)器贩、concatMap()(有序的flatMap)、buffer()朋截、groupBy()(進(jìn)行分組蛹稍,每個分組都會返回一個被觀察者)、scan()(將數(shù)據(jù)按照一定邏輯聚合起來)质和、window()(規(guī)定幾個數(shù)據(jù)分為一組)
組合操作符:concat()(多個組合稳摄,按照之前順序稚字、最多4個)饲宿、concatArray()(可多于4個)厦酬、merge()(并行發(fā)送事件)、concatArrayDelayError()&mergeArrayDelayError()(在 concatArray() 和 mergeArray() 兩個方法當(dāng)中瘫想,如果其中有一個被觀察者發(fā)送了一個 Error 事件仗阅,那么就會停止發(fā)送事件,如果你想 onError() 事件延遲到所有被觀察者都發(fā)送完事件后再執(zhí)行的話)国夜、zip()(會將多個被觀察者合并减噪,根據(jù)各個被觀察者發(fā)送事件的順序一個個結(jié)合起來,最終發(fā)送的事件數(shù)會和源Observable中最少事件的數(shù)量一樣)车吹、combineLatest()&combineLatestDelayError()(類似zip()筹裕,發(fā)送事件的序列是與發(fā)送的時間線有關(guān))、reduce()(與 scan() 操作符的作用也是將發(fā)送數(shù)據(jù)以一定邏輯聚合起來窄驹,這兩個的區(qū)別在于 scan() 每處理一次數(shù)據(jù)就會將事件發(fā)送給觀察者朝卒,而 reduce() 會將所有數(shù)據(jù)聚合在一起才會發(fā)送事件給觀察者)、collect()(收集到數(shù)據(jù)結(jié)構(gòu)中)乐埠、startWith()&startWithArray()(發(fā)送前追加事件)抗斤、count()(返回被觀察者發(fā)送事件的數(shù)量)
功能操作符:delay()、doOnEach()(每發(fā)送一事件前都會先回調(diào)這個方法)丈咐、doOnNext()(onNext()之前)瑞眼、doAfterNext()、doOnComplete()棵逊、doOnError()伤疙、doOnSubscribe()、doOnDispose()(Disposable 的 dispose() 之后)辆影、doOnLifecycle()(在回調(diào) onSubscribe 之前回調(diào)該方法的第一個參數(shù)的回調(diào)方法掩浙,可以使用該回調(diào)方法決定是否取消訂閱)、doOnTerminate()&doAfterTerminate()(doOnTerminate 是在 onError 或者 onComplete 發(fā)送之前回調(diào)秸歧,而 doAfterTerminate 則是 onError 或者 onComplete 發(fā)送之后回調(diào))厨姚、doFinally()、onErrorReturn()(當(dāng)接受到一個 onError() 事件之后回調(diào)键菱,返回的值會回調(diào) onNext() 方法谬墙,并正常結(jié)束該事件序列)、onErrorResumeNext()(返回一個新的 Observable)经备、onExceptionResumeNext()(只能捕獲Exception)拭抬、retry(long times)(重新發(fā)送所有事件序列)、retryUntil(final BooleanSupplier stop)(判斷是否繼續(xù)發(fā)送事件)侵蒙、retryWhen()造虎、repeat()、repeatWhen()纷闺、subscribeOn()(指定被觀察者的線程算凿,要注意的時份蝴,如果多次調(diào)用此方法,只有第一次有效)氓轰、observeOn()(指定觀察者的線程婚夫,每指定一次就會生效一次)
過濾操作符:filter()、ofType(final Class<U> clazz)(可以過濾不符合該類型事件)署鸡、skip(long count)(跳過事件數(shù)量)案糙、distinct()(去掉重復(fù)事件)、distinctUntilChanged()(去掉連續(xù)重復(fù)事件)靴庆、take(long count)(觀察者接收事件數(shù)量)时捌、debounce()(如果兩件事件發(fā)送的時間間隔小于設(shè)定的時間間隔則前一件事件就不會發(fā)送給觀察者)、firstElement()&lastElement()(事件序列的)炉抒、elementAt()&elementAtOrError()
條件操作符:all()(判斷事件序列是否全部滿足某個事件)匣椰、takeWhile()(滿足條件時就會發(fā)送該數(shù)據(jù))、skipWhile()端礼、takeUntil()(當(dāng)事件滿足此條件時禽笑,下一次的事件就不會被發(fā)送了)、skipUntil()蛤奥、sequenceEqual()(兩個Observable發(fā)送的事件是否相同)佳镜、contains()、isEmpty()凡桥、amb()蟀伸、defaultEmpty()(只發(fā)送一個 onComplete() 事件,則可以利用這個方法發(fā)送一個值)缅刽、
references