雖然現在寫RxJava可能都算考古了,但是畢竟是Google爸爸都推薦使用的框架,還是寫一哈吧。以前對於RxJava其實也都是看別人的博客,也沒有抽出時間好好去整理一下知識點,今天就用這篇博客鞏固下之前的知識,查缺補漏吧~
RxJava
- 1. 簡介
- 2. RxJava中使用的設計模式
- 3. RxJava使用方式
- 3.1 重點元素
- 3.1.1 被觀察者(Observable)
- 3.1.1.1 Flowable/Subscriber:
- 3.1.1.2 Observable/Observer:
- 3.1.1.3 Single/SingleObserver:
- 3.1.1.3 Completable/CompletableObserver:
- 3.1.1.3 Maybe/MaybeObserver:
- 3.1.2 觀察者(Observer)
- 3.1.3 訂閱(subscribe)
- 3.1.4 背壓(Backpressure)
- 3.1.5 線程調度器(Schedulers)
- 3.1.6 事件調度器(CompositeDisposable)
- 3.2 Api介紹:
- 3.2.1 create()
- 3.2.2 just()
- 3.2.3 From
- 3.2.4 defer()
- 3.2.5 timer()
- 3.2.6 interval()
- 3.2.7 empty() & never() & error()
- 3.2.8 map()
- 3.2.9 flatMap()
- 3.2.10 concatMap()
- 3.2.11 repeat()
- 3.2.12 subscribeOn()
- 3.2.13 observeOn()
- 3.2.14 subscribe()
- 3.3 具體使用示例代碼
- 4. RxJava在Android中的應用場景
- 5. 拓展
1. 簡介
1.1 官方介紹
ReactiveX是Reactive Extensions的縮寫,一般簡寫爲Rx,最初是LINQ的一個擴展,由微軟的架構師Erik Meijer領導的團隊開發,在2012年11月開源,Rx是一個編程模型,目標是提供一致的編程接口,幫助開發者更方便的處理異步數據流,Rx近幾年越來越流行了,現在已經支持幾乎全部的流行編程語言了,Rx的大部分語言庫由ReactiveX這個組織負責維護,比較流行的有RxJava/RxJS/Rx.NET,社區網站是 reactivex.io。它擴展了觀察者模式以支持數據/事件序列,並添加了運算符,使您可以聲明性地將序列組合在一起,同時消除了對諸如低級線程,同步,線程安全和併發數據結構之類的問題的擔憂。
RxJava是Reactive Extensions的Java VM實現:該庫用於通過使用可觀察的序列來組成異步和基於事件的程序。
1.2 依賴
implementation "io.reactivex.rxjava3:rxjava:3.x.y"
1.3 Hello World 示例代碼
package rxjava.examples;
import io.reactivex.rxjava3.core.*;
public class HelloWorld {
public static void main(String[] args) {
Flowable.just("Hello world").subscribe(System.out::println);
}
}
1.4 RxJava3 新特性
我之前使用的RxJava版本都是RxJava2,現在RxJava已經升級到3了,看一下新特性吧~
主要變化
特點
- 單一依賴:Reactive-Streams
- 繼續支持Java 6+和Android 2.3+
- 修復了API錯誤和RxJava 2的許多限制
- 旨在替代RxJava 2,具有相對較少的二進制不兼容更改
- 提供Java 8 lambda友好的API
- 關於併發源的不同意見
- 異步或同步執行
- 參數化併發的虛擬時間和調度程序
- 爲測試schedulers,consumers和plugin hooks提供測試和診斷支持
與RxJava 2的主要區別是:
- 將eagerTruncate添加到replay運算符,以便head節點將在截斷時丟失它保留的項引用
- 新增 X.fromSupplier()
- 使用 Scheduler 添加 concatMap,保證 mapper 函數的運行位置
- 新增 startWithItem 和 startWithIterable
- ConnectableFlowable/ConnetableFlowable 重新設計
- 將 as() 併入 to()
- 更改 Maybe.defaultIfEmpty() 以返回 Single
- 用 Supplier 代替 Callable
- 將一些實驗操作符推廣到標準
- 從某些主題/處理器中刪除 getValues()
- 刪除 replay(Scheduler) 及其重載
- 刪除 dematerialize()
- 刪除 startWith(T|Iterable)
- 刪除 as()
- 刪除 Maybe.toSingle(T)
- 刪除 Flowable.subscribe(4 args)
- 刪除 Observable.subscribe(4 args)
- 刪除 Single.toCompletable()
- 刪除 Completable.blockingGet()
1.5 技能樹
一個新的框架或者技術開始學習的時候往往無從下手,不知道從哪裏開始,東啃一點西啃一點效率會比較低。我個人的方法是學習之前先大概瞭解其功能和所需要的技術儲備,畫出一個技能樹出來,這樣比較清晰明瞭,不至於像沒頭蒼蠅一樣亂撞。
簡單畫一個RxJava的技能樹:
2. RxJava中使用的設計模式
RxJava是響應式編程(Reactive Extensions)的java實現,它基於觀察者模式的實現了異步編程接口。
學習RxJava首先需要了解什麼是觀察者模式。
需要了解可以看筆者的另外一篇博客:
地址:觀察者模式
Android最重要的線程機制就是耗時操作比如網絡請求和數據庫查詢等需要放在子線程中操作,而對UI的更改必須放在主線程中。傳統的解決方案是使用Handler,AsyncTast或者接口回調,而現在流行的則是使用觀察者模式,用的最多的肯定是這篇的主角RxJava,除此之外還有EventBus,Jetpack框架中提供的LiveData等。
RxJava最基本的被觀察者對象的創建使用了鏈式調用的Builder模式,這種模式普遍在各種第三方框架中使用,關於Builder模式可以參考我的這篇博客:
地址:Builder建造者模式
3. RxJava使用方式
3.1 重點元素
3.1.1 被觀察者(Observable)
可觀察對象,在Rx中定義爲更強大的Iterable,在觀察者模式中是被觀察的對象,一旦數據產生或發生變化,會通過某種方式通知觀察者或訂閱者
3.1.1.1 Flowable/Subscriber:
Flowable是支持背壓的,也就是說,一般而言,上游的被觀察者會響應下游觀察者的數據請求,下游調用request(n)來告訴上游發送多少個數據。這樣避免了大量數據堆積在調用鏈上,使內存一直處於較低水平。
3.1.1.2 Observable/Observer:
這種觀察者模型不支持背壓:當被觀察者快速發送大量數據時,下游不會做其他處理,即使數據大量堆積,調用鏈也不會報MissingBackpressureException,消耗內存過大隻會OOM。
3.1.1.3 Single/SingleObserver:
只能發送單個數據或者一個錯誤Single類似於Observable,不同的是,它總是隻發射一個值,或者一個錯誤通知,而不是發射一系列的值(當然就不存在背壓問題),所以當你使用一個單一連續事件流,這樣你可以使用Single。Single觀察者只包含兩個事件,一個是正常處理成功的onSuccess,另一個是處理失敗的onError。因此,不同於Observable需要三個方法onNext, onError, onCompleted,訂閱Single只需要兩個方法:
- onSuccess - Single發射單個的值到這個方法
- onError - 如果無法發射需要的值,Single發射一個Throwable對象到這個方法
Single只會調用這兩個方法中的一個,而且只會調用一次,調用了任何一個方法之後,訂閱關係終止。
3.1.1.3 Completable/CompletableObserver:
沒有發送任何數據,但只處理 onComplete 和 onError 事件。如果你的觀察者連onNext事件都不關心,可以使用Completable。
3.1.1.3 Maybe/MaybeObserver:
能夠發射0或者1個數據,要麼成功,要麼失敗。如果你有一個需求是可能發送一個數據或者不會發送任何數據,這時候你就需要Maybe,它類似於Single和Completable的混合體。
Maybe可能會調用以下其中一種情況(也就是所謂的Maybe):
- onSuccess或者onError
- onComplete或者onError
3.1.2 觀察者(Observer)
觀察者對象,監聽Observable發射的數據並做出響應,Subscriber是它的一個特殊實現
3.1.3 訂閱(subscribe)
觀察者對象訂閱被觀察者對象,使得被觀察者發佈新內容時觀察者可以得到通知。
RxJava這個方法是屬於被觀察者對象的(Observable),看上去邏輯是反的,主要是爲了鏈式調用的實現,不影響使用,理解概念就行。
3.1.4 背壓(Backpressure)
當上下游在不同的線程中,通過Observable發射,處理,響應數據流時,如果上游發射數據的速度快於下游接收處理數據的速度,這樣對於那些沒來得及處理的數據就會造成積壓,這些數據既不會丟失,也不會被垃圾回收機制回收,而是存放在一個異步緩存池中,如果緩存池中的數據一直得不到處理,越積越多,最後就會造成內存溢出,這便是響應式編程中的背壓(backpressure)問題。
爲此,RxJava帶來了backpressure的概念。背壓是一種流量的控制步驟,在不知道上流還有多少數據的情形下控制內存的使用,表示它們還能處理多少數據。背壓是指在異步場景中,被觀察者發送事件速度遠快於觀察者的處理速度的情況下,一種告訴上游的被觀察者降低發送速度的策略
在Rxjava1.0中,有的Observable支持背壓,有的不支持,爲了解決這種問題,2.0把支持背壓和不支持背壓的Observable區分開來:支持背壓的有Flowable類,不支持背壓的有Observable,Single, Maybe and Completable類。
在訂閱的時候如果使用FlowableSubscriber,那麼需要通過s.request(Long.MAX_VALUE)去主動請求上游的數據項。如果遇到背壓報錯的時候,FlowableSubscriber默認已經將錯誤try-catch,並通過onError()進行回調,程序並不會崩潰;
在訂閱的時候如果使用Consumer,那麼不需要主動去請求上游數據,默認已經調用了s.request(Long.MAX_VALUE)。如果遇到背壓報錯、且對Throwable的Consumer沒有new出來,則程序直接崩潰;
背壓策略的上游的默認緩存池是128。
背壓策略:
- error, 緩衝區大概在128
- buffer, 緩衝區在1000左右
- drop, 把存不下的事件丟棄
- latest, 只保留最新的
3.1.5 線程調度器(Schedulers)
對於Android開發者而言,RxJava最簡單的是通過調度器來方便地切換線程。在不同平臺還有不同的調度器,例如我們Android的主線程:AndroidSchedulers.mainThread()。
調度器 | 功能 |
---|---|
AndroidSchedulers.mainThread() | 需要引用rxandroid, 切換到UI線程 |
Schedulers.computation() | 用於計算任務,如事件循環和回調處理,默認線程數等於處理器數量 |
Schedulers.io() | 用於IO密集型任務,如異步阻塞IO操作,這個調度器的線程池會根據需求,它默認是一個CacheThreadScheduler |
Schedulers.newThread() | 爲每一個任務創建一個新線程 |
Schedulers.trampoline() | 在當前線程中立刻執行,如當前線程中有任務在執行則將其暫停, 等插入進來的任務執行完成之後,在將未完成的任務繼續完成。 |
Scheduler.from(executor) | 指定Executor作爲調度器 |
3.1.6 事件調度器(CompositeDisposable)
RxJava事件發出去並不是置之不顧,要有合理的管理者來管理它們,在合適的時機要進行釋放事件,這樣纔不會導致內存泄漏,這裏的管理者我們稱爲事件調度器(或事件管理者)CompositeDisposable。
3.2 Api介紹:
3.2.1 create()
public static <T> Observable<T> create(ObservableOnSubscribe<T> source)
作用: 創建一個被觀察者
示例:
Observable<String> observable = Observable.create(new ObservableOnSubscribe<String>() {
@Override
public void subscribe(ObservableEmitter<String> e) throws Exception {
e.onNext("Hello Observer");
e.onComplete();
}
});
3.2.2 just()
public static <T> Observable<T> just(T item)
......
public static <T> Observable<T> just(T item1, T item2, T item3, T item4, T item5, T item6, T item7, T item8, T item9, T item10)
作用: 創建一個被觀察者,併發送事件,發送的事件不可以超過10個以上。
示例:
Observable.just(1, 2, 3)
.subscribe(new Observer < Integer > () {
@Override
public void onSubscribe(Disposable d) {
Log.d(TAG, "=================onSubscribe");
}
@Override
public void onNext(Integer integer) {
Log.d(TAG, "=================onNext " + integer);
}
@Override
public void onError(Throwable e) {
Log.d(TAG, "=================onError ");
}
@Override
public void onComplete() {
Log.d(TAG, "=================onComplete ");
}
});
3.2.3 From
3.2.3.1 fromArray()
public static <T> Observable<T> fromArray(T... items)
作用: 這個方法和 just() 類似,只不過 fromArray 可以傳入多於10個的變量,並且可以傳入一個數組。
示例:
Integer array[] = {1, 2, 3, 4};
Observable.fromArray(array)
.subscribe(new Observer < Integer > () {
@Override
public void onSubscribe(Disposable d) {
Log.d(TAG, "=================onSubscribe");
}
@Override
public void onNext(Integer integer) {
Log.d(TAG, "=================onNext " + integer);
}
@Override
public void onError(Throwable e) {
Log.d(TAG, "=================onError ");
}
@Override
public void onComplete() {
Log.d(TAG, "=================onComplete ");
}
});
3.2.3.2 fromCallable()
public static <T> Observable<T> fromCallable(Callable<? extends T> supplier)
作用: 這裏的 Callable 是 java.util.concurrent 中的 Callable,Callable 和 Runnable 的用法基本一致,只是它會返回一個結果值,這個結果值就是發給觀察者的。
示例:
Observable.fromCallable(new Callable < Integer > () {
@Override
public Integer call() throws Exception {
return 1;
}
})
.subscribe(new Consumer < Integer > () {
@Override
public void accept(Integer integer) throws Exception {
Log.d(TAG, "================accept " + integer);
}
});
3.2.3.3 fromFuture()
public static <T> Observable<T> fromFuture(Future<? extends T> future)
作用: 參數中的 Future 是 java.util.concurrent 中的 Future,Future 的作用是增加了 cancel() 等方法操作 Callable,它可以通過 get() 方法來獲取 Callable 返回的值。
示例:
FutureTask < String > futureTask = new FutureTask < > (new Callable < String > () {
@Override
public String call() throws Exception {
Log.d(TAG, "CallableDemo is Running");
return "返回結果";
}
});
Observable.fromFuture(futureTask)
.doOnSubscribe(new Consumer < Disposable > () {
@Override
public void accept(Disposable disposable) throws Exception {
futureTask.run();
}
})
.subscribe(new Consumer < String > () {
@Override
public void accept(String s) throws Exception {
Log.d(TAG, "================accept " + s);
}
});
3.2.3.4 fromIterable()
public static <T> Observable<T> fromIterable(Iterable<? extends T> source)
作用: 直接發送一個 List 集合數據給觀察者
示例:
List<Integer> list = new ArrayList<>();
list.add(0);
list.add(1);
list.add(2);
list.add(3);
Observable.fromIterable(list)
.subscribe(new Observer < Integer > () {
@Override
public void onSubscribe(Disposable d) {
Log.d(TAG, "=================onSubscribe");
}
@Override
public void onNext(Integer integer) {
Log.d(TAG, "=================onNext " + integer);
}
@Override
public void onError(Throwable e) {
Log.d(TAG, "=================onError ");
}
@Override
public void onComplete() {
Log.d(TAG, "=================onComplete ");
}
});
3.2.4 defer()
public static <T> Observable<T> defer(Callable<? extends ObservableSource<? extends T>> supplier)
作用: 這個方法的作用就是直到被觀察者被訂閱後纔會創建被觀察者。
示例:
// i 要定義爲成員變量
Integer i = 100;
Observable<Integer> observable = Observable.defer(new Callable<ObservableSource<? extends Integer>>() {
@Override
public ObservableSource<? extends Integer> call() throws Exception {
return Observable.just(i);
}
});
i = 200;
Observer observer = new Observer<Integer>() {
@Override
public void onSubscribe(Disposable d) {
}
@Override
public void onNext(Integer integer) {
Log.d(TAG, "================onNext " + integer);
}
@Override
public void onError(Throwable e) {
}
@Override
public void onComplete() {
}
};
observable.subscribe(observer);
i = 300;
observable.subscribe(observer);
3.2.5 timer()
public static Observable<Long> timer(long delay, TimeUnit unit)
......
作用: 當到指定時間後就會發送一個 0L 的值給觀察者。
示例:
Observable.timer(2, TimeUnit.SECONDS)
.subscribe(new Observer < Long > () {
@Override
public void onSubscribe(Disposable d) {
}
@Override
public void onNext(Long aLong) {
Log.d(TAG, "===============onNext " + aLong);
}
@Override
public void onError(Throwable e) {
}
@Override
public void onComplete() {
}
});
3.2.6 interval()
public static Observable<Long> interval(long period, TimeUnit unit)
public static Observable<Long> interval(long initialDelay, long period, TimeUnit unit)
......
作用: 每隔一段時間就會發送一個事件,這個事件是從0開始,不斷增1的數字。
示例:
Observable.interval(4, TimeUnit.SECONDS)
.subscribe(new Observer < Long > () {
@Override
public void onSubscribe(Disposable d) {
Log.d(TAG, "==============onSubscribe ");
}
@Override
public void onNext(Long aLong) {
Log.d(TAG, "==============onNext " + aLong);
}
@Override
public void onError(Throwable e) {
}
@Override
public void onComplete() {
}
});
3.2.7 empty() & never() & error()
public static <T> Observable<T> empty()
public static <T> Observable<T> never()
public static <T> Observable<T> error(final Throwable exception)
作用:
- empty() : 直接發送 onComplete() 事件
- never():不發送任何事件
- error():發送 onError() 事件
示例:
Observable.empty()
.subscribe(new Observer < Object > () {
@Override
public void onSubscribe(Disposable d) {
Log.d(TAG, "==================onSubscribe");
}
@Override
public void onNext(Object o) {
Log.d(TAG, "==================onNext");
}
@Override
public void onError(Throwable e) {
Log.d(TAG, "==================onError " + e);
}
@Override
public void onComplete() {
Log.d(TAG, "==================onComplete");
}
});
3.2.8 map()
public final <R> Observable<R> map(Function<? super T, ? extends R> mapper)
作用: map 可以將被觀察者發送的數據類型轉變成其他的類型
示例:
Observable.just(1, 2, 3)
.map(new Function < Integer, String > () {
@Override
public String apply(Integer integer) throws Exception {
return "I'm " + integer;
}
})
.subscribe(new Observer < String > () {
@Override
public void onSubscribe(Disposable d) {
Log.e(TAG, "===================onSubscribe");
}
@Override
public void onNext(String s) {
Log.e(TAG, "===================onNext " + s);
}
@Override
public void onError(Throwable e) {
}
@Override
public void onComplete() {
}
});
3.2.9 flatMap()
public final <R> Observable<R> flatMap(Function<? super T, ? extends ObservableSource<? extends R>> mapper)
......
作用: 這個方法可以將事件序列中的元素進行整合加工,返回一個新的被觀察者。
示例:
public class Person {
private String name;
private List<Plan> planList = new ArrayList<>();
public Person(String name, List<Plan> planList) {
this.name = name;
this.planList = planList;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public List<Plan> getPlanList() {
return planList;
}
public void setPlanList(List<Plan> planList) {
this.planList = planList;
}
}
3.2.10 concatMap()
public final <R> Observable<R> concatMap(Function<? super T, ? extends ObservableSource<? extends R>> mapper)
public final <R> Observable<R> concatMap(Function<? super T, ? extends ObservableSource<? extends R>> mapper, int prefetch)
作用: concatMap() 和 flatMap() 基本上是一樣的,只不過 concatMap() 轉發出來的事件是有序的,而 flatMap() 是無序的。
示例:
Observable.fromIterable(personList)
.flatMap(new Function < Person, ObservableSource < Plan >> () {
@Override
public ObservableSource < Plan > apply(Person person) {
if ("chan".equals(person.getName())) {
return Observable.fromIterable(person.getPlanList()).delay(10, TimeUnit.MILLISECONDS);
}
return Observable.fromIterable(person.getPlanList());
}
})
.subscribe(new Observer < Plan > () {
@Override
public void onSubscribe(Disposable d) {
}
@Override
public void onNext(Plan plan) {
Log.d(TAG, "==================plan " + plan.getContent());
}
@Override
public void onError(Throwable e) {
}
@Override
public void onComplete() {
}
});
3.2.11 repeat()
public final Observable<T> repeat(long times)
......
作用: 重複發送被觀察者的事件,times 爲發送次數。
示例:
Observable.create(new ObservableOnSubscribe < Integer > () {
@Override
public void subscribe(ObservableEmitter < Integer > e) throws Exception {
e.onNext(1);
e.onNext(2);
e.onNext(3);
e.onComplete();
}
})
.repeat(2)
.subscribe(new Observer < Integer > () {
@Override
public void onSubscribe(Disposable d) {
Log.d(TAG, "===================onSubscribe ");
}
@Override
public void onNext(Integer integer) {
Log.d(TAG, "===================onNext " + integer);
}
@Override
public void onError(Throwable e) {
}
@Override
public void onComplete() {
Log.d(TAG, "===================onComplete ");
}
});
3.2.12 subscribeOn()
public final Observable<T> subscribeOn(Scheduler scheduler)
作用: 指定被觀察者的線程,要注意的時,如果多次調用此方法,只有第一次有效。
示例:
Observable.create(new ObservableOnSubscribe < Integer > () {
@Override
public void subscribe(ObservableEmitter < Integer > e) throws Exception {
Log.d(TAG, "=========================currentThread name: " + Thread.currentThread().getName());
e.onNext(1);
e.onNext(2);
e.onNext(3);
e.onComplete();
}
})
//.subscribeOn(Schedulers.newThread())
.subscribe(new Observer < Integer > () {
@Override
public void onSubscribe(Disposable d) {
Log.d(TAG, "======================onSubscribe");
}
@Override
public void onNext(Integer integer) {
Log.d(TAG, "======================onNext " + integer);
}
@Override
public void onError(Throwable e) {
Log.d(TAG, "======================onError");
}
@Override
public void onComplete() {
Log.d(TAG, "======================onComplete");
}
});
3.2.13 observeOn()
public final Observable<T> observeOn(Scheduler scheduler)
作用: 指定觀察者的線程,每指定一次就會生效一次。
示例:
Observable.just(1, 2, 3)
.observeOn(Schedulers.newThread())
.flatMap(new Function < Integer, ObservableSource < String >> () {
@Override
public ObservableSource < String > apply(Integer integer) throws Exception {
Log.d(TAG, "======================flatMap Thread name " + Thread.currentThread().getName());
return Observable.just("chan" + integer);
}
})
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Observer < String > () {
@Override
public void onSubscribe(Disposable d) {
Log.d(TAG, "======================onSubscribe");
}
@Override
public void onNext(String s) {
Log.d(TAG, "======================onNext Thread name " + Thread.currentThread().getName());
Log.d(TAG, "======================onNext " + s);
}
@Override
public void onError(Throwable e) {
Log.d(TAG, "======================onError");
}
@Override
public void onComplete() {
Log.d(TAG, "======================onComplete");
}
});
3.2.14 subscribe()
public final void subscribe(Observer<? super T> observer)
作用: 觀察者與被觀察者建立訂閱關係
示例:
observable.subscribe(observer);
以上API由剛哥整理,原文更加完整,我這裏只收錄些常用的
3.3 具體使用示例代碼
先上Code吧,之前在簡介裏貼上的HelloWolrd是RxJava3官方提供的示例代碼。
目前大部分項目還是在用RxJava2,我用RxJava2的代碼先介紹使用方式吧。
- 添加依賴
/* RxJava*/
implementation "com.squareup.retrofit2:converter-gson:2.4.0"
implementation "com.squareup.retrofit2:adapter-rxjava2:2.4.0"
implementation "io.reactivex.rxjava2:rxandroid:2.1.0"
- 創建被觀察者對象
Observable observable =Observable.create(new ObservableOnSubscribe<String>() {
/*
* 重寫subscribe方法
*/
@Override
public void subscribe(ObservableEmitter<String> emitter) throws Exception {
//被觀察者進行數據操作,如數據庫查詢,在OnNext中返回結果
...
emitter.onNext("OnNext1");
emitter.onNext("OnNext2");
emitter.onNext("OnNext3");
emitter.onComplete();
}
});
如果只關心OnNext中的值可以這麼寫,會自動幫你補上onComplete()
Observable observable = Observable.just("OnNext1","OnNext2","OnNext3");
或者
String [] kk={"OnNext1","OnNext1","OnNext3"};
Observable observable = Observable.from(kk);
ObservableEmitter有三種發射的方法,分別是void onNext(T value)、void onError(Throwable error)、void onComplete(),onNext方法可以無限調用,Observer(觀察者)所有的都能接收到,onError和onComplete是互斥的,Observer(觀察者)只能接收到一個,OnComplete可以重複調用,但是Observer(觀察者)只會接收一次,而onError不可以重複調用,第二次調用就會報異常。
- 創建觀察者對象
Observer<String> observer=new Observer<String>() {
@Override
public void onSubscribe(Disposable d) {
mDisposable=d;
Log.e(TAG,"onSubscribe");
}
@Override
public void onNext(String value) {
if ("OnNext".equals(value)){
//這裏可以使用拿到的結果去更新UI
mDisposable.dispose();
return;
}
Log.e(TAG,"onNext:"+value);
}
@Override
public void onError(Throwable e) {
Log.e(TAG,"onError="+e.getMessage());
}
@Override
public void onComplete() {
Log.e(TAG,"onComplete()");
}
};
- 觀察者和被觀察者建立訂閱關係
observable
.observeOn(AndroidSchedulers.mainThread())//主線程回調
.subscribeOn(Schedulers.io())//子線程處理邏輯
.subscribe(observer);//訂閱
前面說到了RxJava支持鏈式調用,觀察者對象和被觀察者對象也可以使用匿名內部類的方式放在鏈式調用中,這樣可以一行代碼實現一次Android中的子線程數據操作主線程跟新UI的操作了。
4. RxJava在Android中的應用場景
前面寫的最基本的RxJava使用示例代碼其實和其他方案相比在Android中優勢並不大,移動設備上主要的耗時操作還是網絡請求和數據庫查詢。對於這兩個方面主流的網絡請求框架Retrofit和Jetpack組件中的Room數據庫都給RxJava提供了支持,使得Android可以更加便捷優雅地使用RxJava進行開發。
4.1 RxJava配合Retrofit使用
添加依賴
//Retrofit依賴
implementation 'com.squareup.retrofit2:retrofit:2.4.0'
implementation 'com.squareup.retrofit2:converter-gson:2.4.0'
//Rxjava and Retrofit(Retrofit+Rx需要添加的依賴)
implementation 'com.squareup.retrofit2:adapter-rxjava:2.4.0'
implementation "io.reactivex.rxjava2:rxandroid:2.1.0"
implementation 'io.reactivex.rxjava2:rxjava:2.2.2'
implementation "com.squareup.retrofit2:converter-gson:2.4.0"
Retrofit不使用RxJava的使用方式這裏就不展開說了。直接看使用RxJava的情況。
創建一個自定義類型:
private long id;
private String name;
private int age;
private String sex;
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
webService:
public interface WebService{
@GET("xxxx")//請求路徑
Observable<User> getUser();
}
不使用RxJava的時候webService通常是返回一個Call對象,這裏把Call對象變爲了RxJava的Observable對象。也就是說通過網絡請求返回的是一個被觀察者對象。
聯網請求代碼:
基礎版本:
private void getUsersFromServer() {
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(API.BASE_URL)//基礎URL 建議以 / 結尾
.addConverterFactory(GsonConverterFactory.create())//設置 Json 轉換器
.addCallAdapterFactory(RxJavaCallAdapterFactory.create())//RxJava 適配器
.build();
WebService webService= retrofit.create(WebService.class);
webService.getUser()
.subscribeOn(Schedulers.io())//IO線程加載數據
.observeOn(AndroidSchedulers.mainThread())//主線程顯示數據
.subscribe(new Subscriber<User>() {
@Override
public void onCompleted() {
}
@Override
public void onError(Throwable e) {
}
@Override
public void onNext(User user) {
}
});
}
其實Retrofit返回的結果我們只需要知道onNext() 的內容或者onError() 返回的錯誤就可以了。
Observable的subscribe的重載方法中有兩個參數的方法
@CheckReturnValue
@SchedulerSupport(SchedulerSupport.NONE)
public final Disposable subscribe(Consumer<? super T> onNext, Consumer<? super Throwable> onError) {
return subscribe(onNext, onError, Functions.EMPTY_ACTION, Functions.emptyConsumer());
}
爲了代碼的簡潔我們可以這麼寫
webService.getUser()
.observeOn(AndroidSchedulers.mainThread())//主線程回調
.subscribeOn(Schedulers.io())//子線程處理邏輯
.subscribe(new Consumer<String>() {
@Override
public void accept(String s) throws Exception {
}
}, new Consumer<Throwable>() {
@Override
public void accept(Throwable throwable) throws Exception {
}
});
此時會有警告The result of subscribe
is not used,原因爲AS並不知道這個沒有使用(分解)的訂閱會有什麼潛在的風險,例如:若在事件流中有耗時操作,同時事件流中某個事件又持有了Activity的引用,那麼當Activity被關閉時,其引用仍會被未結束的事件所持有,會造成內存泄露;另外當Activity生命週期走到destroy後(注意:並不是Activity對象被回收),之後Activity中的view卻要根據事件結果設置屬性,則可能導致空指針異常(view的引用已被釋放)。
爲了解決這個警告我們只要把Disposable提煉出來然後在使用完畢後調用dispose()方法釋放就好了。之前的兩個Consumer類型參數可以使用Lambda表達式進一步簡化。
Disposable disposable = webService.getUser()
.observeOn(AndroidSchedulers.mainThread())//主線程回調
.subscribeOn(Schedulers.io())//子線程處理邏輯
.subscribe( user->{
Log.d(TAG,user.getName());//返回結果處理
}, Throwable::printStackTrace);//異常處理
disposable.dispose();
OK, 關於RxJava和Retrofit的組合使用就到這裏,有興趣可以把這部分code封裝一下,這樣自己使用起來更加簡潔方便。
4.2 RxJava配合Room使用
之前我寫過一篇Room+LiveData的
LiveData結合Room數據庫使用以及線程問題
RxJava+Room的使用其實差不多,就不詳細講了
給出Android官方文檔中Demo地址:JetPack Demo
UserDao中返回類型寫RxJava中對應的Observable類型
Dao
public interface UserDao {
@Query("SELECT * FROM user")
Single<List<User>> getUserSingle();
@Query("SELECT * FROM user")
Maybe<List<User>> getUserMaybe();
@Query("SELECT * FROM user")
Flowable<List<User>> getUserFlowable();
@Query("SELECT * FROM user")
Observable<List<User>> getUserObservable();
@Insert
void insert(User user);
@Delete
void delect(User user);
@Update
void update(User user);
}
userDao.getUserObservable()
. subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(list->{},Throwable::printStackTrace)
5. 拓展
5.1 RxBus
事件總線的好處在於方便組件之間的交互,RxBus不是一個庫,而是使用RxJava實現事件總線的一種思想。剛好項目中使用到了rxjava,相對於使用eventbus,使用rxbus來的更方便。
關於RxBus的使用可以參考這篇博客
RxBus在rxjava2.0 的基本使用
5.2 與其他方案的對比
5.2.1 與Handler對比
Handler是Android原生方案,也可以簡潔的解決異步問題。但是因爲內存泄漏問題需要使用弱引用,而且對於複雜邏輯的編寫沒有RxJava那麼簡潔優雅。我個人現在寫項目已經儘量不使用Handler了,但是這也不代表Handler會被取代,Handler的作用是通訊,線程切換隻是它的功能之一,除了線程間通訊配合Messenger使用Handler還可以進行進程間通訊。畢竟Android就是由消息機制驅動的,ActivityThread的開始和結束就是主線程Looper的循環開始和跳出。
5.2.2 與AsyncTask對比
AsyncTask同樣是Android原生方案,但是需要大量模板代碼,代碼簡潔度和RxJava更是不能相比,我以前就不喜歡用,Handler完全可以替代它。
5.2.3 與LiveData對比
LiveData屬於Google Jetpack框架,它的特點是數據始終保持最新狀態,並且可以感知LifeCycle,自己管理生命週期。但無法像RxJava那樣在一個stream同時發送數據或異常,缺少豐富的stream操作符,不支持鏈式操作。LiveData用於觀察本地數據變化綁定UI比RxJava好用,但是在網絡請求上我們一般一次請求接收一次數據,而不需要實時變化,RxJava+Retrofit我認爲是最優解。LiveData目前還沒有全面替代RxJava的能力。