RxJava2
Rx介紹
Rx是一個函數庫,讓開發者可以利用可觀察序列和LINQ風格查詢操作符來編寫異步和基於事件的程序,使用Rx,開發者可以用Observables表示異步數據流,用LINQ操作符查詢異步數據流,用Scheduler參數化異步數據流的併發處理。
Rx可以這樣定義:Rx = Observables + LINQ + Schedulers
官方定義:Rx是一個使用可觀察數據流進行異步編程的編程接口,Rx結合了觀察者模式、迭代器模式和函數式編程的精華。
- Q1:什麼是LINQ風格?
a) LINQ是另外一種數據抽象層;
b) LINQ是所有類型數據的統一編程模型,它可以讓你使用一致的模型查詢和使用數據,而不用關心數據源是什麼。 - Q2 : 迭代器模式?
迭代器模式就是分離了集合對象的遍歷行爲,抽象出一個迭代器類來負責,這樣既可以做到不暴露集合的內部結構,又可讓外部代碼透明地訪問集合內部的數據。 - Q3 :函數式編程?
函數式編程關心類型(代數結構)之間的關係,命令式編程關心解決問題的步驟
相關學習地址
ReactiveX文檔中文翻譯
github首頁
通過gradle引入
(其中x和y表示最新版本號)
compile “io.reactivex.rxjava2:rxjava:2.x.y”
github鏈接:https://github.com/ReactiveX/RxJava
官方例子
入門使用
- Flowable.just(“Hello world!”)
.subscribe(new Consumer(){
@Override
public void accept(String s){
System.out.println(s);
}
});
在後臺線程上運行一些計算和網絡請求
並在UI線程上顯示結果(或錯誤)
-
Flowable.fromCallable(()->{
Thread.sleep(“1000”); //模擬耗時操作
return “Done”;
})
.subscribeOn(Schedulers.io())
.observeOn(Schedulers.single())
.subscribe(System.out::println,Throwable::printStackTrace);這種方法調用我們稱之爲鏈式調用(fluent API),類似於構建者模式。但是RxJava的響應式返回類型是不變的;每一次的方法調用都只會返回一個新的具有可添加行爲的Flowable對象。爲了驗證這一點,以上方法可以被改寫爲:
Flowable source;
Flowable runBackground;
Flowable showForeground;source=Flowable.formCallable(() ->{
Thread.sleep(1000);
return “Done”;
});runBackground=source
.subscribeOn(Schedulers.io());showForeground=runBackgounrd
.observeOn(Schedulers.single());showForeground
.subscribe(System.out::println, Throwable::printStackTrace)
一些術語
Reactive
- 直譯爲反應性的,有活性的,根據上下文一般翻譯爲反應式、響應式
Iterable
- 可迭代對象,支持以迭代器的形式遍歷,許多語言中都存在這個概念
Observable
- 可觀察對象,在Rx中定義爲更強大的Iterable,在觀察者模式中是被觀察的對象,一旦數據產生或發生變化,會通過某種方式通知觀察者或訂閱者
Observer
- 觀察者對象,監聽Observable發射的數據並做出響應,Subscriber是它的一個特殊實現
emit
- 直譯爲發射,發佈,發出,含義是Observable在數據產生或變化時發送通知給Observer,調用Observer對應的方法,文章裏一律譯爲發射
items
- 譯爲項目,條目,在Rx裏是指Observable發射的數據項,文章裏一律譯爲數據,數據項
backpressure
背壓
-
數據流發射,處理,響應可能在各自的線程中獨立進行,上游在發射數據的時候,不知道下游是否處理完,也不會等下游處理完之後再發射。
這樣,如果上游發射的很快而下游處理的很慢,會怎樣呢?
數據流通過異步步驟運行時,這種情況將會產生很多下游沒來得及處理的數據,這些數據既不會丟失,也不會被垃圾回收機制回收,而是存放在一個異步緩存池中,如果緩存池中的數據一直得不到處理,越積越多,最後就會造成內存溢出,這便是Rxjava中的背壓問題。
在RxJava中,專用Flowable類指定支持背壓,Observable專門用於非背壓操作(短序列、GUI交互等)。其它類型Single,Maybe和Completable不支持背壓,也不應該支持背壓,總是有空間暫時存放一個item項目
Upstream,downStream
上游和下游
-
RxJava中的數據流包括一個源、0個或多箇中間步驟,後跟
數據使用者或組合步驟(其中該步驟負責通過某種方式使用數據流)
例子:
source.operator1().operator2().operator3().subscribe(consumer);
( operator1是operator2的上游,operator3是operator2的下游,表達了用戶/消費者的權利 )
Objects in motion
運動中的對象
在RxJava的文檔中,發射(emission),發射(emit),項目(item),事件(event),信號(signal),數據(data)和消息(message)被認爲是同義詞,並代表沿着數據流傳播的對象。
“冷”與“熱”
-
從Observable什麼時候開始發射數據序列上看: 冷的Observable -> 等待訂閱纔開開始發射數據 熱的Observable -> 無需等待訂閱,直接發射item
一些關鍵類
簡介
-
Flowable是爲了解決背壓(backpressure)問題的
a) Flowable是Publisher與Subscriber這一觀察者模式中Publisher的典型實現
b) Observable是ObservableSource/Observer這一組觀察者模式中ObservableSource的典型實現;
-
一個可觀察對象(Observable),觀察者(Observer)訂閱(Subscribe)它,當數據就緒時,之前定義的機制就會分發數據給一直處於等待狀態的觀察者哨兵。
-
Single類似於Observable,不同的是,它總是隻發射一個值,或者一個錯誤通知,而不是發射一系列的值。 因此,不同於Observable需要三個方法onNext, onError, onCompleted,訂閱Single只需要兩個方法: onSuccess - Single發射單個的值到這個方法 onError - 如果無法發射需要的值,Single發射一個Throwable對象到這個方法 Single只會調用這兩個方法中的一個,而且只會調用一次,調用了任何一個方法之後,訂閱關係終止..
-
Intenationnal chool
一個橋樑或者代理,同時充當了Observer和Observable的角色。即它可以訂閱一個或者多個的Observable也可以轉發它收到的數據或者發射新的數據 一共有四種類型Subject:
a)AsyncSubject :
只在原始Observable完成後,發射來自原始Observable的最後一個值。它會把這最後一個值發射給任何後續的觀察者。
b)BehaviorSubject:
當觀察者訂閱BehaviorSubject時,它開始發射原始Observable最近發射的數據,然後繼續發射其它任何來自原始Observable的數據.
c)PublishSubject::
只會把訂閱發生的時間點之後的來自原始Observable的數據發射給觀察者。需要注意的是它可能會一創建完成就立刻開始發射數據,有風險存在:在Subject被創建後到有觀察者訂閱它之前的這個時間段內,一個或者多個數據可能會丟失,
d)ReplaySubject:
會發射所有來自原始Observable的數據給觀察者,無論它們是何時訂閱的。注意:用作一個觀察者時,注意不要從多個線程中調用它的onNext等等系列,這可能導致同時(非順序)調用,這會違反Observable協議,給Subject的結果增加了不確定性。
Rx模式
使用觀察者模式
- 創建:Rx可以方便地創建事件流和數據流
- 組合:Rx使用查詢式的操作符組合變換數據流
- 監聽:Rx可以訂閱任何可觀察的數據流並執行操作
簡化代碼
- 函數式風格:
對可觀察數據流使用無副作用的輸入輸出函數,
避免了程序裏錯綜複雜的狀態 - 簡化代碼:
Rx的操作符通常可以將複雜的難題簡化爲很少的幾行代碼 - 異步錯誤處理:
傳統的try/catch沒辦法處理異步計算,Rx提供了合適的錯誤
處理機制 - 輕鬆使用併發:
Rx的Observables和Schedulers讓開發者可以擺脫底層的線程
同步和各種併發問題
operator操作符
創建操作
-
create
- 使用一個函數從頭開始創建一個Observable
create方法默認不在任何特定的調度器上執行
- 使用一個函數從頭開始創建一個Observable
-
Defer
- 直到有觀察者訂閱時才創建Observable,並且爲每個觀察者創建一個新的Observable,即每個訂閱者獲取的是專屬的單獨的數據序列
-
Empty/Never/Throw
- Empty:創建一個不發射任何數據但是正常終止的Observable
Never: 創建一個不發射數據也不終止的Observable
Throw: 創建一個不發射數據以一個錯誤終止的Observable.
總結: 測試的時候很有用
- Empty:創建一個不發射任何數據但是正常終止的Observable
-
From
- 將其它種類的對象和數據類型轉換爲Observable
在RxJava中,from操作符可以轉換Future、Iterable和數組
- 將其它種類的對象和數據類型轉換爲Observable
-
Interval
- 創建一個按固定時間間隔發射整數序列的Observable
-
Just
- 創建一個發射指定值的Observable
-
Range
- 創建一個發射特定整數序列的Observable
-
Repeat
- 創建一個發射特定數據重複多次的Observable
-
Start
- 返回一個Observable,它發射一個類似於函數聲明的值
-
Timer
- 創建一個Observable,它在一個給定的延遲後發射一個特殊的值。
Observable.timer(2, TimeUnit.SECONDS); //間隔2s發射
- 創建一個Observable,它在一個給定的延遲後發射一個特殊的值。
變換操作
-
Buffer
- 定期收集Observable的數據放進一個數據包裹,然後發射這些數據包裹,而不是一次發射一個值,RxJava中有許多Buffer的變體
-
FlatMap
-
FlatMap操作符使用一個指定的函數對原始Observable發射的每一項數據執行變換操作,這個函數這個函數返回一個本身也發射數據的Observable,然後FlatMap合併這些Observables發射的數據,最後將合併後的結果當做它自己的數據序列發射。將一個發射數據的Observable變換爲多個Observables,然後將它們發射的數據合併後放進一個單獨的Observable
-
-
GroupBy
- 將一個Observable分拆爲一些Observables集合,它們中的每一個發射原始Observable的一個子序列
-
Map
- 對Observable發射的每一項數據應用一個函數,執行變換操作
-
Scan
- 連續地對數據序列的每一項應用一個函數,然後連續發射結果
-
Window
- 定期將來自原始Observable的數據分界爲一個Observable窗口,發射這些窗口,而不是每次發射一項數據
過濾操作
-
Debounce
- 僅在過了一段指定的時間還沒發射數據時才發射一個數據
-
Distinct
- 抑制(過濾掉)重複的數據項
-
ElementAt
- 只發射第N項數據
-
Filter
- 只發射通過了謂詞測試的數據項
-
First
- 只發射第一項(或者滿足某個條件的第一項)數據
-
IgnoreElements
- 不發射任何數據,只發射Observable的終止通知
-
Last
- 只發射最後一項(或者滿足某個條件的最後一項)數據
-
Sample
- 定期發射Observable最近發射的數據項
-
Skip
- 抑制Observable發射的前N項數據
-
SkipLast
- 抑制Observable發射的後N項數據
-
Take
- 只發射前面的N項數據
-
TakeLast
- 發射Observable發射的最後N項數據
結合操作
-
And/Then/When
- 使用Pattern和Plan作爲中介,將兩個或多個Observable發射的數據集合併到一起
-
CombineLatest
- 當兩個Observables中的任何一個發射了數據時,使用一個函數結合每個Observable發射的最近數據項,並且基於這個函數的結果發射數據。
-
Join
- 任何時候,只要在另一個Observable發射的數據定義的時間窗口內,這個Observable發射了一條數據,就結合兩個Observable發射的數據。
-
Merge
- 合併多個Observables的發射物
-
StartWith
- 在數據序列的開頭插入一條指定的項
-
Switch
- 將一個發射多個Observables的Observable轉換成另一個單獨的Observable,後者發射那些Observables最近發射的數據項
-
Zip
- 通過一個函數將多個Observables的發射物結合到一起,基於這個函數的結果爲每個結合體發射單個數據項。
錯誤處理
-
Catch
- Catch操作符攔截原始Observable的onError通知,將它替換爲其它的數據項或數據序列,讓產生的Observable能夠正常終止或者根本不終止。
-
Retry
- 如果原始Observable遇到錯誤,重新訂閱它期望它能正常終止
輔助操作
-
Delay
- 延遲一段指定的時間再發射來自Observable的發射物
-
Do
- 註冊一個動作作爲原始Observable生命週期事件的一種佔位符
-
Materialize/Dematerialize
- Materialize將數據項和事件通知都當做數據項發射,Dematerialize剛好相反
-
ObserveOn
- 指定一個觀察者在哪個調度器上觀察這個Observable
-
Serialize
- 強制一個Observable連續調用並保證行爲正確
-
Subscribe
- 操作來自Observable的發射物和通知
-
SubscribeOn
- 指定Observable自身在哪個調度器上執行
-
TimeInterval
- 將一個發射數據的Observable轉換爲發射那些數據發射時間間隔的Observable
-
Timeout
- 對原始Observable的一個鏡像,如果過了一個指定的時長仍沒有發射數據,它會發一個錯誤通知
-
Timestamp
- 給Observable發射的數據項附加一個時間戳
-
Using
- 創建一個只在Observable生命週期內存在的一次性資源
-
To
- 將Observable轉換爲另一個對象或數據結構
條件和布爾操作
- All/Contains/Amb
- DefaultEmpty
- SequenceEqual
- SkipUntil/SkipWhile
- TakeUntil/TakeWhile
算術和聚合操作
-
Average/Concat/Reduce
-
Max/Min/Count/Sum
連接操作
- Connect
關注Fragment和Activity的生命週期
在Android上,要在異步操作中訪問框架中的對象有些棘手,那是因爲Andoid系統可以決定銷燬(destroy)一個 Activity,例如,當一個後臺線程還在運行的時候,如果這個線程嘗試訪問一個已經死掉的Activity中的View對象,會導致異常退出(Crash)。(這也會導致內存泄露,因爲 Activity 已經不可見了,你的後臺線程還持有它的引用。)
這仍然是在Android上使用RxJava需要關注的一個問題,但是通過使用 Subscription和其它Observable操作符,你可以優雅地解決這個問題。通常來說,當你在Activity中訂閱一個Observable的結果時(無論是直接的還是通過一個內部類),你必須在 onDestroy 裏取消訂閱,就像下面例子裏展示的那樣:(可以考慮使用Rxlifecycle自動防止內存泄漏問題)
MyActivityprivate Subscription subscription;
protected void onCreate(Bundle savedInstanceState) {
this.subscription = observable.subscribe(this);
}
protected void onDestroy() {
this.subscription.unsubscribe();
super.onDestroy();
}