通常情況下,如果我們想要使用 RxJava 首先會想到的是使用Observable,如果要考慮到Backpressure的情況,在 RxJava2.x 時代我們會使用Flowable。除了Observable和Flowable之外,在 RxJava2.x 中還有三種型別的Observables:Single、Completable、Maybe。
型別 | 描述 |
---|---|
Observable |
能夠發射0或n個資料,並以成功或錯誤事件終止。 |
Flowable |
能夠發射0或n個資料,並以成功或錯誤事件終止。 支援Backpressure,可以控制資料來源發射的速度。 |
Single |
只發射單個資料或錯誤事件。 |
Completable | 它從來不發射資料,只處理 onComplete 和 onError 事件。可以看成是Rx的Runnable。 |
Maybe |
能夠發射0或者1個資料,要麼成功,要麼失敗。有點類似於Optional |
從上面的表格可以看出,這五種被觀察者型別中只有Flowable能支援Backpressure,如果有需要Backpressure的情況,還是必須要使用Flowable。
Single
從SingleEmitter的原始碼可以看出,Single 只有 onSuccess 和 onError 事件。
/**
* Copyright (c) 2016-present, RxJava Contributors.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License is
* distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See
* the License for the specific language governing permissions and limitations under the License.
*/
package io.reactivex;
import io.reactivex.annotations.*;
import io.reactivex.disposables.Disposable;
import io.reactivex.functions.Cancellable;
/**
* Abstraction over an RxJava {@link SingleObserver} that allows associating
* a resource with it.
* <p>
* All methods are safe to call from multiple threads.
* <p>
* Calling onSuccess or onError multiple times has no effect.
*
* @param <T> the value type to emit
*/
public interface SingleEmitter<T> {
/**
* Signal a success value.
* @param t the value, not null
*/
void onSuccess(@NonNull T t);
/**
* Signal an exception.
* @param t the exception, not null
*/
void onError(@NonNull Throwable t);
/**
* Sets a Disposable on this emitter; any previous Disposable
* or Cancellation will be unsubscribed/cancelled.
* @param s the disposable, null is allowed
*/
void setDisposable(@Nullable Disposable s);
/**
* Sets a Cancellable on this emitter; any previous Disposable
* or Cancellation will be unsubscribed/cancelled.
* @param c the cancellable resource, null is allowed
*/
void setCancellable(@Nullable Cancellable c);
/**
* Returns true if the downstream cancelled the sequence.
* @return true if the downstream cancelled the sequence
*/
boolean isDisposed();
}複製程式碼
其中,onSuccess()用於發射資料(在Observable/Flowable中使用onNext()來發射資料)。而且只能發射一個資料,後面即使再發射資料也不會做任何處理。
Single的SingleObserver中只有onSuccess、onError,並沒有onComplete。這是 Single 跟其他四種被觀察者最大的區別。
Single.create(new SingleOnSubscribe<String>() {
@Override
public void subscribe(@NonNull SingleEmitter<String> e) throws Exception {
e.onSuccess("test");
}
}).subscribe(new Consumer<String>() {
@Override
public void accept(@NonNull String s) throws Exception {
System.out.println(s);
}
}, new Consumer<Throwable>() {
@Override
public void accept(@NonNull Throwable throwable) throws Exception {
throwable.printStackTrace();
}
});複製程式碼
上面的程式碼,由於Observer中有兩個Consumer,還可以進一步簡化成
Single.create(new SingleOnSubscribe<String>() {
@Override
public void subscribe(@NonNull SingleEmitter<String> e) throws Exception {
e.onSuccess("test");
}
}).subscribe(new BiConsumer<String, Throwable>() {
@Override
public void accept(String s, Throwable throwable) throws Exception {
System.out.println(s);
}
});複製程式碼
Single 可以通過toXXX方法轉換成Observable、Flowable、Completable以及Maybe。
Completable
Completable在建立後,不會發射任何資料。從CompletableEmitter的原始碼可以看到
/**
* Copyright (c) 2016-present, RxJava Contributors.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License is
* distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See
* the License for the specific language governing permissions and limitations under the License.
*/
package io.reactivex;
import io.reactivex.annotations.*;
import io.reactivex.disposables.Disposable;
import io.reactivex.functions.Cancellable;
/**
* Abstraction over an RxJava {@link CompletableObserver} that allows associating
* a resource with it.
* <p>
* All methods are safe to call from multiple threads.
* <p>
* Calling onComplete or onError multiple times has no effect.
*/
public interface CompletableEmitter {
/**
* Signal the completion.
*/
void onComplete();
/**
* Signal an exception.
* @param t the exception, not null
*/
void onError(@NonNull Throwable t);
/**
* Sets a Disposable on this emitter; any previous Disposable
* or Cancellation will be disposed/cancelled.
* @param d the disposable, null is allowed
*/
void setDisposable(@Nullable Disposable d);
/**
* Sets a Cancellable on this emitter; any previous Disposable
* or Cancellation will be disposed/cancelled.
* @param c the cancellable resource, null is allowed
*/
void setCancellable(@Nullable Cancellable c);
/**
* Returns true if the downstream disposed the sequence.
* @return true if the downstream disposed the sequence
*/
boolean isDisposed();
}複製程式碼
Completable 只有 onComplete 和 onError 事件,同時 Completable 並沒有map、flatMap等操作符,它的操作符比起 Observable/Flowable 要少得多。
我們可以通過fromXXX操作符來建立一個Completable。這是一個Completable版本的Hello World。
Completable.fromAction(new Action() {
@Override
public void run() throws Exception {
System.out.println("Hello World");
}
}).subscribe();複製程式碼
Completable 經常會結合andThen操作符
Completable.create(new CompletableOnSubscribe() {
@Override
public void subscribe(@NonNull CompletableEmitter emitter) throws Exception {
try {
TimeUnit.SECONDS.sleep(1);
emitter.onComplete();
} catch (InterruptedException e) {
emitter.onError(e);
}
}
}).andThen(Observable.range(1, 10))
.subscribe(new Consumer<Integer>() {
@Override
public void accept(@NonNull Integer integer) throws Exception {
System.out.println(integer);
}
});複製程式碼
在這裡emitter.onComplete()執行完之後,表明Completable已經完全執行完畢,接下來是執行andThen裡的操作。
列印結果如下:
1
2
3
4
5
6
7
8
9
10複製程式碼
在Completable中,andThen有多個過載的方法,正好對應了五種被觀察者的型別。
Completable andThen(CompletableSource next)
<T> Maybe<T> andThen(MaybeSource<T> next)
<T> Observable<T> andThen(ObservableSource<T> next)
<T> Flowable<T> andThen(Publisher<T> next)
<T> Single<T> andThen(SingleSource<T> next)複製程式碼
Completable 也可以通過toXXX方法轉換成Observable、Flowable、Single以及Maybe。
在網路操作中,如果遇到更新的情況,也就是Restful架構中的PUT操作,一般要麼返回原先的物件要麼只提示更新成功。下面兩個介面使用了Retrofit,分別是用於獲取簡訊驗證碼和更新使用者資訊,其中更新使用者資訊如果用PUT會更符合Restful的API。
/**
* 獲取簡訊驗證碼
* @param param
* @return
*/
@POST("v1/user-auth")
Completable getVerificationCode(@Body VerificationCodeParam param);
/**
* 使用者資訊更新介面
* @param param
* @return
*/
@POST("v1/user-update")
Completable update(@Body UpdateParam param);複製程式碼
在model類中大致會這樣寫。
/**
* Created by Tony Shen on 2017/7/24.
*/
public class VerificationCodeModel extends HttpResponse {
/**
* 獲取驗證碼
* @param activity
* @param param
* @return
*/
public Completable getVerificationCode(AppCompatActivity activity, VerificationCodeParam param) {
return apiService
.getVerificationCode(param)
.compose(RxJavaUtils.<VerificationCodeModel>completableToMain())
.compose(RxLifecycle.bind(activity).<VerificationCodeModel>toLifecycleTransformer());
}
}複製程式碼
特別要注意的是getVerificationCode返回的是Completable而不是Completable
獲取驗證碼成功則給出相應地toast提示,失敗可以做出相應地處理。
VerificationCodeModel model = new VerificationCodeModel();
model.getVerificationCode(RegisterActivity.this,param)
.subscribe(new Action() {
@Override
public void run() throws Exception {
showShort(RegisterActivity.this,"傳送驗證碼成功");
}
},new RxException<Throwable>(){
@Override
public void accept(@NonNull Throwable throwable) throws Exception {
throwable.printStackTrace();
......
}
});複製程式碼
Maybe
Maybe 是 RxJava2.x 之後才有的新型別,可以看成是Single和Completable的結合。
Maybe建立之後,MaybeEmitter 和 SingleEmitter 一樣並沒有onNext()方法,同樣需要通過onSuccess()方法來發射資料。
Maybe.create(new MaybeOnSubscribe<String>() {
@Override
public void subscribe(@NonNull MaybeEmitter<String> e) throws Exception {
e.onSuccess("testA");
}
}).subscribe(new Consumer<String>() {
@Override
public void accept(@NonNull String s) throws Exception {
System.out.println("s="+s);
}
});複製程式碼
列印出來的結果是
s=testA複製程式碼
Maybe也只能發射0或者1個資料,即使發射多個資料,後面發射的資料也不會處理。
Maybe.create(new MaybeOnSubscribe<String>() {
@Override
public void subscribe(@NonNull MaybeEmitter<String> e) throws Exception {
e.onSuccess("testA");
e.onSuccess("testB");
}
}).subscribe(new Consumer<String>() {
@Override
public void accept(@NonNull String s) throws Exception {
System.out.println("s="+s);
}
});複製程式碼
列印出來的結果仍然是
s=testA複製程式碼
跟第一次執行的結果是一致的。
如果MaybeEmitter先呼叫了onComplete(),即使後面再呼叫了onSuccess()也不會發射任何資料。
Maybe.create(new MaybeOnSubscribe<String>() {
@Override
public void subscribe(@NonNull MaybeEmitter<String> e) throws Exception {
e.onComplete();
e.onSuccess("testA");
}
}).subscribe(new Consumer<String>() {
@Override
public void accept(@NonNull String s) throws Exception {
System.out.println("s="+s);
}
});複製程式碼
這次就沒有列印任何資料了。
我們對上面的程式碼再做一下修改,在subscribe()中也加入onComplete(),看看列印出來的結果會是這樣的?因為SingleObserver中是沒有onComplete()方法。
Maybe.create(new MaybeOnSubscribe<String>() {
@Override
public void subscribe(@NonNull MaybeEmitter<String> e) throws Exception {
e.onComplete();
e.onSuccess("testA");
}
}).subscribe(new Consumer<String>() {
@Override
public void accept(@NonNull String s) throws Exception {
System.out.println("s=" + s);
}
}, new Consumer<Throwable>() {
@Override
public void accept(@NonNull Throwable throwable) throws Exception {
}
}, new Action() {
@Override
public void run() throws Exception {
System.out.println("Maybe onComplete");
}
});複製程式碼
這次列印的結果是
Maybe onComplete複製程式碼
通過檢視Maybe相關的原始碼
@CheckReturnValue
@SchedulerSupport(SchedulerSupport.NONE)
public final Disposable subscribe(Consumer<? super T> onSuccess, Consumer<? super Throwable> onError,
Action onComplete) {
ObjectHelper.requireNonNull(onSuccess, "onSuccess is null");
ObjectHelper.requireNonNull(onError, "onError is null");
ObjectHelper.requireNonNull(onComplete, "onComplete is null");
return subscribeWith(new MaybeCallbackObserver<T>(onSuccess, onError, onComplete));
}複製程式碼
我們可以得到,Maybe在沒有資料發射時候subscribe會呼叫MaybeObserver的onComplete()。如果Maybe有資料發射或者呼叫了onError(),是不會再執行MaybeObserver的onComplete()。
我們也可以將 Maybe 轉換成Observable、Flowable、Single,只需相應地呼叫toObservable()、toFlowable()、toSingle()。
接下來我們再來看看 Maybe 跟 Retrofit 是怎樣結合使用的?
下面的網路請求,最初返回的型別是Flowable,但是這個網路請求並不是一個連續事件流,我們只會發起一次 Post 請求返回資料並且只收到一個事件。因此,可以考慮將 onComplete() 可以跟 onNext() 合併。在這裡,嘗試我們將Flowable改成Maybe。
@POST("v1/contents")
Maybe<ContentModel> loadContent(@Body ContentParam param);複製程式碼
在model類中,我們大致會這樣寫。
public class ContentModel extends HttpResponse {
public List<ContentItem> data;
/**
* 獲取內容
* @param fragment
* @param param
* @param cacheKey
* @return
*/
public Maybe<ContentModel> getContent(Fragment fragment,ContentParam param,String cacheKey) {
return apiService.loadContent(param)
.compose(RxLifecycle.bind(fragment).<ContentModel>toLifecycleTransformer())
.compose(RxJavaUtils.<ContentModel>maybeToMain())
.compose(RxUtils.<ContentModel>toCacheTransformer(cacheKey,App.getInstance().cache));
}
......
}複製程式碼
其中,maybeToMain()方法是用Kotlin編寫的工具方法,這些工具方法由Kotlin來編寫會顯得比較簡單和清晰,特別是lambda表示式更加直觀。
@JvmStatic
fun <T> maybeToMain(): MaybeTransformer<T, T> {
return MaybeTransformer{
upstream ->
upstream.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
}
}複製程式碼
最後是真正地使用model類,如果網路請求成功則將資料展示到recyclerview上,如果失敗也會做出相應地處理。
model.getContent(this,param,cacheKey)
.subscribe(new Consumer<ContentModel>() {
@Override
public void accept(@io.reactivex.annotations.NonNull ContentModel model) throws Exception {
adapter = new NewsAdapter(mContext, model);
recyclerview.setAdapter(adapter);
spinKitView.setVisibility(View.GONE);
}
}, new RxException<Throwable>() {
@Override
public void accept(@NonNull Throwable throwable) throws Exception {
throwable.printStackTrace();
spinKitView.setVisibility(View.GONE);
......
}
});複製程式碼
總結
RxJava 有五種不同型別的被觀察者,合理地使用它們能夠寫出更簡潔優雅的程式碼。這些被觀察者在一定程度上也能夠作一些相互轉換。值得注意的是,只有Flowable是支援Backpressure的,其餘四種都不支援。