[英]Getting error “Callable returned null” when using RxJava2
我在我的 android 項目中使用 RxJava2。
我正在使用以下代碼來創建Observable
public Observable<AlbumDetails> loadAlbumFromAlbumId(final String albumId) {
return Observable.fromCallable(new Callable<AlbumDetails>() {
@Override
public AlbumDetails call() throws Exception {
AlbumDetails albumDetails = getAlbumDetails(albumId);
return albumDetails;
});
}
從 observable 中,我在 DisposableObserver 的 onError 方法中收到以下錯誤
Callable returned null
使用 RxJava 時不會發生這種情況。
我曾經有這樣的代碼:
Observable<R> obs = Observable.fromCallable(this::work);
work() 可能會返回null
,正如您所指出的,RxJava 2 對此並不滿意。
Observable<R> obs = Maybe.fromCallable(this::work).toObservable();
通過這種方式,最終消費者——觀察者——只有在 work() 有任何返回時才會開始。 如果 work() 返回 null 那么它和訂閱一個空的 Observer 是一樣的; 沒發生什么事。
Observable<R> obs = Observable.create(e -> {
R r = work();
if (r != null) {
e.onNext(r);
}
e.onComplete();
});
出於多種原因,將每個發射包裝在一個Optional
= 壞主意中。
主要是因為我只在我的 API 中使用 Optional 如果它是預期的,並且是“正常”場景,你時不時會得到一個空值。 如果 null 不是預期的或非常罕見,可能是同一消費者完成的另一個 API 調用的直接結果,那么我返回 null 並讓消費者在這些特殊情況下處理它,而不是讓每個消費者都處理 Optional地方。
正如維基中給出的:
RxJava 2.x 不再接受空值。 將 null 作為流元素會立即導致NullPointerException
並因此調用 onError 方法。
這樣做主要是為了避免由於應用程序中的NullPointerException
而導致的崩潰。
我通過一個相當簡單的方法解決了這個問題。 我檢查了該值是否為空,如果是,我用占位符對象替換了空值。
還存在其他更復雜的方法來解決這個問題,但對於我的用例,這種簡單的方法就足夠了。
RxJava 2.x 不再接受空值而不實現錯誤處理程序
例子
Observable.fromCallable(() -> null)
.subscribe(System.out::println, Throwable::printStackTrace);
Observable.just(1).map(v -> null)
.subscribe(System.out::println, Throwable::printStackTrace);
您的問題的解決方案
當您調用/訂閱此方法時,請執行以下操作
Observable<AlbumDetails> testObservable= Observable.create(emitter -> { ... });
testObservable.subscribe(t -> System.out.print(t),Throwable::printStackTrace);
假設getAlbumDetails(albumId)
方法在數據不可用或錯誤的情況下返回null
,並且您願意在這種情況下優雅地完成流,您可以使用以下內容:
public Observable<AlbumDetails> loadAlbumFromAlbumId(String albumId) {
return Maybe.fromCallable(() -> getAlbumDetails(albumId))
.onErrorComplete()
.toObservable();
};
為了更好的可讀性,我已經用 lambda 替換了匿名類,但你當然可以保持原樣。
您還可以將返回值包裝在 Optional (Java 8) 中。 以及您訂閱中使用 optional.isPresent() 和 optional.get() 的地圖。
我想出了這個解決方法:
首先創建了一個包裝類:
class NullableObject<T>(val value: T?)
然后為 Single 創建了一個擴展函數,如下所示:
inline fun <T> runInSingle(
crossinline block: () -> T,
crossinline callback: (T?) -> Unit,
crossinline onError: (Throwable) -> Unit) {
Single.fromCallable {
return@fromCallable block().toNullableObject()
}.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe { result, error ->
if (error != null) {
onError(error)
} else {
callback(result.value)
}
}
}
fun <T> T.toNullableObject(): NullableObject<T> = NullableObject(this)
如何使用 :
runInSingle({
doSomethingInBackgroundWhichMayReturnNull()
}, { result ->
if(result != null) {
doSomethingWithTheNonNullResult()
} else {
doSomethingWithTheNullResult()
}
}, { error ->
error.printStackTrace()
})
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.