RxJava中的線程
默認的情況下,Observable 和 Observer是處在同一線程的,發送事件在哪個線程,處理事件同樣也在該線程。
在Activity的onCreate方法中運行以下代碼:
Observable.create(new ObservableOnSubscribe<Integer>() {
@Override
public void subscribe(@NonNull ObservableEmitter<Integer> e) throws Exception {
Log.d("RxJava", "Observable Thread: " + Thread.currentThread().getName());
e.onNext(1);
}
})
.subscribe(new Consumer<Integer>() {
@Override
public void accept(@NonNull Integer integer) throws Exception {
Log.d("RxJava", "Observer Thread: " + Thread.currentThread().getName());
}
});
可以得到以下結果:
D/RxJava: Observable Thread: main
D/RxJava: Observer Thread: main
RxJava中,使用Scheduler來進行線程控制,從而實現了關鍵的異步操作。
Scheduler
Scheduler可以稱之為線程調度器,它指定了發送和處理事件所在的線程。常用的API有以下幾個:
- Schedulers.newThread():啟用新線程并在新線程運行
- Schedulers.io():進行I/O 操作所使用的Scheduler,它的內部實現是一個無上限的線程池,可以重用空閑線程,比newThread更有效率,通常用于讀寫文件,數據庫,網絡操作等。
- Schedulers.computation():CPU密集計算所用的Scheduler,它內部是一個線程數等于CPU核心數的線程池。
- AndroidSchedulers.mainThread(): Android中的主線程(UI線程)。
介紹完了常用API之后,通過下面的例子來看一下是怎樣使用的:
Observable.create(new ObservableOnSubscribe<Integer>() {
@Override
public void subscribe(@NonNull ObservableEmitter<Integer> e) throws Exception {
Log.d("RxJava", "Observable Thread: " + Thread.currentThread().getName());
e.onNext(1);
}
})
.subscribeOn(Schedulers.newThread())//指定observable線程
.observeOn(AndroidSchedulers.mainThread())//指定Observer線程
.subscribe(new Consumer<Integer>() {
@Override
public void accept(@NonNull Integer integer) throws Exception {
Log.d("RxJava", "Observer Thread: " + Thread.currentThread().getName());
}
});
還是上面的例子,加了兩行代碼,subscribeOn和observeOn。subscribeOn用來指定發送事件的線程,即事件產生的線程,observeOn指定接收并處理事件的線程,即事件消費線程。運行結果如下:
D/RxJava: Observable Thread: RxNewThreadScheduler-1
D/RxJava: Observer Thread: main
subscribeOn和observeOn都可以多次設置,但是subscribeOn只有第一次設置的值會生效,而observeOn不一樣,觀察者會按照observeOn的指定順序依次切換到最后一個線程。
操作符
操作符的作用是在事件發送的過程中完成一些特定的操作,比如對事件的包裝,添加額外的動作等等。常用操作符主要有以下幾種:
-
map();
map的作用是將observable的數據進行加工,轉換成一個新的數據之后再進行發送。看一個具體的例子:
Observable.create(new ObservableOnSubscribe<Integer>() {
@Override
public void subscribe(@NonNull ObservableEmitter<Integer> e) throws Exception {
e.onNext(1);
e.onNext(2);
e.onNext(3);
}
})
.map(new Function<Integer, String>() {
@Override
public String apply(@NonNull Integer integer) throws Exception {
return "This is Data No. " + integer ;
}
})
.subscribe(new Consumer<String>() {
@Override
public void accept(@NonNull String str) throws Exception {
Log.d("RxJava", "Received data: " + str);
}
});
輸出結果如下:
D/RxJava: Received data: This is Data No. 1
D/RxJava: Received data: This is Data No. 2
D/RxJava: Received data: This is Data No. 3
-
FlatMap()
FlatMap與map類似,但是功能更強大了。map只是對Observable發送的數據進行處理,返回的是處理后的數據,而FlatMap在數據處理之后返回的是一個Observable對象,所以,FlatMap實際上是對原來的一系列事件進行加工然后分拆,將每一個數據包含在一個新的Observable對象中發送給下游的觀察者。這樣做有什么好處? 舉一個簡單的例子,如果每一個事件都是耗時操作,那么采用FlatMap,將事件分發給不同的Observable,然后加入Schedulers.io(),這樣效率瞬間提高了。示例如下:
Observable.create(new ObservableOnSubscribe<Integer>() {
@Override
public void subscribe(@NonNull ObservableEmitter<Integer> e) throws Exception {
//原始事件,打印線程
Log.d("RxJava", "Original Observable Thread: " + Thread.currentThread().getName());
e.onNext(10);
e.onNext(20);
e.onNext(30);
}
})
.flatMap(new Function<Integer, ObservableSource<String>>() {
@Override
public ObservableSource<String> apply(@NonNull final Integer integer) throws Exception {
return Observable.create(new ObservableOnSubscribe<String>(){
@Override
public void subscribe(@NonNull ObservableEmitter<String> e) throws Exception {
//打印FlatMap轉換后,發送事件的線程
Log.d("RxJava", "Observable Thread: " + Thread.currentThread().getName());
Thread.sleep(1000);
e.onNext("This is Data No." + integer);
}
//指定flatMap轉換后發送事件所處的線程
}).subscribeOn(Schedulers.io());
}
})
//指定原始事件發送線程
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Consumer<String>() {
@Override
public void accept(@NonNull String str) throws Exception {
//打印觀察者所處的線程
Log.d("RxJava", "Observer Thread: " + Thread.currentThread().getName());
Log.d("RxJava", "Received data: " + str);
}
});
運行結果如下:
Original Observable Thread: RxCachedThreadScheduler-1
D/RxJava: Observable Thread: RxCachedThreadScheduler-1
D/RxJava: Observable Thread: RxCachedThreadScheduler-2
D/RxJava: Observable Thread: RxCachedThreadScheduler-3
Observer Thread: main
D/RxJava: Received data: This is Data No.10
D/RxJava: Observer Thread: main
D/RxJava: Received data: This is Data No.20
D/RxJava: Observer Thread: main
D/RxJava: Received data: This is Data No.30
從結果可以看出來,最初的Observable包含3個事件,運行在同一個子線程中,如果是耗時操作,采用同步的方式會浪費大量事件,經過FlatMap轉換之后,將每個事件轉換為一個新的Observable對象,并指定線程,效率一下提高了3倍!
concatMap
這個操作符與FlatMap作用一樣,只是,FlatMap轉換的事件在發送時并不保證順序,而concatMap仍然會按原來的順序發送。filter()
filter用來對發送的數據進行過濾
.filter(new Predicate<Integer>() {
@Override
public boolean test(@NonNull Integer integer) throws Exception {
return false;
}
})
返回值決定了下游觀察者是否能夠收到數據,true表示能收到,false表示不能接收到。
take()
傳入一個long數值,表示取前多少個數據。如果傳入值大于數據量,會全部發送。另外,它還接收時間參數,表示在多長時間內發送的數據會被接收。-
doOnNext()
doOnNext()允許我們在每次輸出一個元素之前做一些額外的事情,比如緩存,調試,等等。
.observeOn(AndroidSchedulers.mainThread())
.doOnNext(new Consumer<Integer>() {
@Override
public void accept(@NonNull Integer integer) throws Exception {
Log.d("RxJava", "onnext2 Observer Thread: " + Thread.currentThread().getName());
}
})