一、背景
在使用RxJava的过程中,经常会碰到如下一个经典的错误:
Observable.range(0, 10)
.subscribeOn(Schedulers.io())
.map(i -> null)
.subscribe();
在上面的代码中,由于我们没有实现onError()的RxJava观察者,所以在运行的时候,会报如下的错误。
io.reactivex.exceptions.OnErrorNotImplementedException: The exception was not handled due to missing onError handler in the subscribe() method call. Further reading: https://github.com/ReactiveX/RxJava/wiki/Error-Handling | The mapper function returned a null value.
at io.reactivex.internal.functions.Functions$OnErrorMissingConsumer.accept(Functions.java:704)
at io.reactivex.internal.functions.Functions$OnErrorMissingConsumer.accept(Functions.java:701)
at io.reactivex.internal.observers.LambdaObserver.onError(LambdaObserver.java:77)
at io.reactivex.internal.observers.BasicFuseableObserver.onError(BasicFuseableObserver.java:100)
at io.reactivex.internal.observers.BasicFuseableObserver.fail(BasicFuseableObserver.java:110)
at io.reactivex.internal.operators.observable.ObservableMap$MapObserver.onNext(ObservableMap.java:59)
at io.reactivex.internal.operators.observable.ObservableSubscribeOn$SubscribeOnObserver.onNext(ObservableSubscribeOn.java:58)
at io.reactivex.internal.operators.observable.ObservableScalarXMap$ScalarDisposable.run(ObservableScalarXMap.java:248)
at io.reactivex.internal.operators.observable.ObservableJust.subscribeActual(ObservableJust.java:35)
at io.reactivex.Observable.subscribe(Observable.java:12090)
at io.reactivex.internal.operators.observable.ObservableSubscribeOn$SubscribeTask.run(ObservableSubscribeOn.java:96)
at io.reactivex.Scheduler$DisposeTask.run(Scheduler.java:578)
at io.reactivex.internal.schedulers.ScheduledRunnable.run(ScheduledRunnable.java:66)
at io.reactivex.internal.schedulers.ScheduledRunnable.call(ScheduledRunnable.java:57)
at java.util.concurrent.FutureTask.run(FutureTask.java:266)
at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access$201(ScheduledThreadPoolExecutor.java:180)
at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:293)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
at java.lang.Thread.run(Thread.java:748)
Caused by: java.lang.NullPointerException: The mapper function returned a null value.
at io.reactivex.internal.functions.ObjectHelper.requireNonNull(ObjectHelper.java:39)
at io.reactivex.internal.operators.observable.ObservableMap$MapObserver.onNext(ObservableMap.java:57)
... 14 more
对于上面的信息,并不是很方便我们定位问题,对于这个问题,我们可以启用RxDogTag来为onError()调查自动标记RxJava 2+原始订阅点。
根据官方的介绍,RxDogTag是一个在rxjava2+观察者中标记原始订阅点的实用程序,其目标是在发生未处理的错误时显示它们的订阅位置,以便以后进行错误报告/调查。这只适用于不实现onError()的RxJava观察者。
二、使用和配置
2.1 基本使用
首先,我们需要在项目中添加RxDogTag的依赖,依赖的时候需要区分是RxJava2还是RxJava3,因为他们的依赖方式是不一样的。
//RxJava2
implementation("com.uber.rxdogtag:rxdogtag:x.y.z")
//RxJava3
implementation("com.uber.rxdogtag2:rxdogtag:x.y.z")
接下来,在应用程序生命周期的早期通过RxDogTag.install()安装,这将在RxJavaPlugins中安装必要的钩子。
RxDogTag.builder()
.configureWith(AutoDisposeConfigurer::configure)
.install();
启用RxDogTag时,错误发生了明显的改变,如下。
io.reactivex.exceptions.OnErrorNotImplementedException: The mapper function returned a null value.
Caused by: java.lang.NullPointerException: The mapper function returned a null value.
at anotherpackage.ReadMeExample.complex(ReadMeExample.java:55)
at [[ ↑↑ Inferred subscribe point ↑↑ ]].(:0)
at [[ ↓↓ Original trace ↓↓ ]].(:0)
at io.reactivex.internal.functions.ObjectHelper.requireNonNull(ObjectHelper.java:39)
at io.reactivex.internal.operators.observable.ObservableMap$MapObserver.onNext(ObservableMap.java:57)
at io.reactivex.internal.operators.observable.ObservableSubscribeOn$SubscribeOnObserver.onNext(ObservableSubscribeOn.java:58)
at io.reactivex.internal.operators.observable.ObservableScalarXMap$ScalarDisposable.run(ObservableScalarXMap.java:248)
at io.reactivex.internal.operators.observable.ObservableJust.subscribeActual(ObservableJust.java:35)
at io.reactivex.Observable.subscribe(Observable.java:12090)
at io.reactivex.internal.operators.observable.ObservableSubscribeOn$SubscribeTask.run(ObservableSubscribeOn.java:96)
at io.reactivex.Scheduler$DisposeTask.run(Scheduler.java:578)
at io.reactivex.internal.schedulers.ScheduledRunnable.run(ScheduledRunnable.java:66)
at io.reactivex.internal.schedulers.ScheduledRunnable.call(ScheduledRunnable.java:57)
at java.util.concurrent.FutureTask.run(FutureTask.java:266)
at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access$201(ScheduledThreadPoolExecutor.java:180)
at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:293)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
at java.lang.Thread.run(Thread.java:748)
启用RxDogTag后,示例订阅行提示报错为ReadMeExample.java:55,经过处理后,就方便我们查找问题了。报告的订阅线还应回溯和分组,以便进行崩溃报告。
2.2 其他配置
RxDogTag有一个替代的RxDogTag.builder()API,以方便添加配置,例如注释控制、stacktrace元素位置等等。
Custom handlers
如果自定义观察者可能修饰了其他观察者类型,则可以通过ObserverHandler接口将此信息传递给RxDogTag。此接口可用于展开这些自定义观察者,以显示其代理及其潜在行为。通过接受处理程序的RxDogTag.Builder#addObserverHandlers(...)
重载来安装这些。
Ignored packages
在检查堆栈跟踪以推断订阅点时,RxDogTag需要忽略某些包(例如它自己的或RxJava的包)。您可以通过RxDogTag.Builder#addIgnoredPackages(...)
添加其他自定义的。
AutoDispose support AutoDispose是一个用于自动处理流的库,它通过自己的装饰观察器进行工作。AutoDispose可以通过其在AutoDisposingObserver接口上的delegateObserver() api与RxDogTag一起工作。使用AutoDispose需要添加如下依赖。
//RxJava 2
implementation("com.uber.rxdogtag:rxdogtag-autodispose:x.y.z")
//RxJava 3
implementation("com.uber.rxdogtag2:rxdogtag-autodispose:x.y.z")
通过单独的rxdogtag-autodispose工件及其AutoDisposeObserverHandler单例实例可以获得对这一点的支持。
RxDogTag.builder()
.configureWith(AutoDisposeConfigurer::configure)
.install();