RxDogTag:自动标记RxJava原始订阅点

895 阅读2分钟

一、背景

在使用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();

参考:github.com/uber/RxDogT…