【Android进阶】RxJava 堆栈异常信息显示不全,怎么搞?

优化Android RxJava2堆栈跟踪 本文还有配套的精品资源,点击获取 简介:RxJava是Android开发中处理异步数据流的反应式编程库。在错误处理和调试中,理解堆栈跟踪是关键。本主题探讨如何通过RxJava2的 rxjava-tracing 模块和自定义插件改善堆栈跟踪信息,以便更有效地定位和解决问题。例如,通过 RxJavaPlugins 的自定义错误处理器和第三方库 ... 阅读详情

原文:徐公

现象

大家好,今天为大家带来的是 RxJava 的一个血案,一行代码 return null 引发的。

前阵子,组内的同事反馈说 RxJava 在 debug 包 crash 了,捕获到的异常信息不全。(即我们捕获到的堆栈没有包含我们自己代码,都是一些系统或者 RxJava 框架的代码)

典型的一些 error 信息如下:

 1 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 | java.lang.NullPointerException: Callable returned null
 2     at io.reactivex.internal.functions.Functions$OnErrorMissingConsumer.accept(Functions.java:704)
 3     at io.reactivex.internal.functions.Functions$OnErrorMissingConsumer.accept(Functions.java:701)
 4     at io.reactivex.internal.observers.LambdaObserver.onError(LambdaObserver.java:77)
 5     at io.reactivex.internal.operators.observable.ObservableObserveOn$ObserveOnObserver.checkTerminated(ObservableObserveOn.java:281)
 6     at io.reactivex.internal.operators.observable.ObservableObserveOn$ObserveOnObserver.drainNormal(ObservableObserveOn.java:172)
 7     at io.reactivex.internal.operators.observable.ObservableObserveOn$ObserveOnObserver.run(ObservableObserveOn.java:255)
 8     at io.reactivex.android.schedulers.HandlerScheduler$ScheduledRunnable.run(HandlerScheduler.java:124)
 9     at android.os.Handler.handleCallback(Handler.java:883)
10     at android.os.Handler.dispatchMessage(Handler.java:100)
11     at android.os.Looper.loop(Looper.java:214)
12     at android.app.ActivityThread.main(ActivityThread.java:7682)
13     at java.lang.reflect.Method.invoke(Native Method)
14     at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:516)
15     at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:950)
16 Caused by: java.lang.NullPointerException: Callable returned null
17     at io.reactivex.internal.functions.ObjectHelper.requireNonNull(ObjectHelper.java:39)
18     at io.reactivex.internal.operators.observable.ObservableFromCallable.subscribeActual(ObservableFromCallable.java:43)
19     at io.reactivex.Observable.subscribe(Observable.java:12267)
20     at io.reactivex.internal.operators.observable.ObservableSubscribeOn$SubscribeTask.run(ObservableSubscribeOn.java:96)
21     at io.reactivex.Scheduler$DisposeTask.run(Scheduler.java:578)
22     at io.reactivex.internal.schedulers.ScheduledRunnable.run(ScheduledRunnable.java:66)
23     at io.reactivex.internal.schedulers.ScheduledRunnable.call(ScheduledRunnable.java:57)
24     at java.util.concurrent.FutureTask.run(FutureTask.java:266)
25     at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:301)
26     at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167)
27     at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641)
28     at java.lang.Thread.run(Thread.java:919)

可以看到,上面的 Error 堆栈信息中,它并没有给出这个 Error 在实际项目中的调用路径。可以看到,报错的堆栈,提供的有效信息较少, 我们只能知道是由于 callable.call() 这里返回了 Null,导致出错。却不能判断 callable 是哪里创建的,这时候我们只能结合日志上下文,判断当前之前的代码大概在哪里,再逐步排查。

 1        public final class ObservableFromCallable<T> extends Observable<T> implements Callable<T> {
 2
 3
 4        @Override
 5        public void subscribeActual(Observer<? super T> observer) {
 6        DeferredScalarDisposable<T> d = new DeferredScalarDisposable<T>(observer);
 7        observer.onSubscribe(d);
 8        if (d.isDisposed()) {
 9            return;
10        }
11        T value;
12        try {
13            // callable.call()  这里返回了 Null,并传递给了 RxJavaPlugins 的 errorHandler
14            value = ObjectHelper.requireNonNull(callable.call(), "Callable returned null");
15        } catch (Throwable e) {
16            Exceptions.throwIfFatal(e);
17            if (!d.isDisposed()) {
18                observer.onError(e);
19            } else {
20                RxJavaPlugins.onError(e);
21            }
22            return;
23        }
24        d.complete(value);
25       }
26
27      }

一顿操作猛如虎,很多,我们结合一些上下文日志,发现是这里返回了 null,导致出错

1    backgroundTask(Callable<Any> {
2    Log.i(TAG, "btn_rx_task: ")
3    Thread.sleep(30)
4    return@Callable null
5    })?.subscribe()

1/**
2 * 创建一个rx的子线程任务Observable
3 */
4    private fun <T> backgroundTask(callable: Callable<T>?): Observable<T>? {
5    return Observable.fromCallable(callable)
6            .compose(IOMain())
7    }

如果遇到 callable 比较多的情况下,这时候 一个个排查 callable,估计搞到你吐血。

那有没有什么较好的方法,比如做一些监控?完整打印堆栈信息。

第一种方案,自定义 Hook 解决

首先,我们先来想一下,什么是堆栈?

在我的理解里面,堆栈是用来储存我们程序当前执行的信息。在 Java 当中,我们通过 java.lang.Thread#getStackTrace 可以拿到当前线程的堆栈信息,注意是当前线程的堆栈。

而 RxJava 抛出异常的地方,是在执行 Callable#call 方法中,它打印的自然是 Callable#call 的方法调用栈,而如果 Callable#call 的调用线程跟 callable 的创建线程不一致,那肯定拿不到 创建 callable 时候的堆栈。

而我们实际上需要知道的是 callable 创建的地方,对应到我们我们项目报错的地方,那自然是 Observable.fromCallable 方法的调用栈。

这时候,我们可以采用 Hook 的方式,来 Hook 我们的代码

为了方便,我们这里采用了 wenshu 大神的 Hook 框架, github, 想自己手动去 Hook 的,可以看一下我两年前写的文章 Android Hook 机制之简单实战,里面有介绍介绍一些常用的 Hook 手段。

很快,我们写出了如下代码,对 Observable#fromCallable 方法进行 hook

 1    fun hookRxFromCallable() {
 2//        DexposedBridge.findAndHookMethod(ObservableFromCallable::class.java, "subscribeActual", Observer::class.java, RxMethodHook())
 3        DexposedBridge.findAndHookMethod(
 4            Observable::class.java,
 5            "fromCallable",
 6            Callable::class.java,
 7            object : XC_MethodHook() {
 8                override fun beforeHookedMethod(param: MethodHookParam?) {
 9                    super.beforeHookedMethod(param)
10                    val args = param?.args
11                    args ?: return
12
13                    val callable = args[0] as Callable<*>
14                    args[0] = MyCallable(callable = callable)
15
16                }
17
18                override fun afterHookedMethod(param: MethodHookParam?) {
19                    super.afterHookedMethod(param)
20                }
21            })
22    }
23
24    class MyCallable(private val callable: Callable<*>) : Callable<Any> {
25
26        private val TAG = "RxJavaHookActivity"
27        val buildStackTrace: String?
28
29        init {
30            buildStackTrace = Rx2Utils.buildStackTrace()
31        }
32
33        override fun call(): Any {
34            Log.i(TAG, "call: ")
35            val call = callable.call()
36            if (call == null) {
37                Log.e(TAG, "call should not return null: buildStackTrace is $buildStackTrace")
38            }
39            return call
40        }
41
42    }

再次执行我们的代码

1    backgroundTask(Callable<Any> {
2    Log.i(TAG, "btn_rx_task: ")
3    Thread.sleep(30)
4    return@Callable null
5    })?.subscribe()

可以看到,当我们的 Callable 返回为 empty 的时候,这时候报错的信息会含有我们项目的代码, perfect。

RxJavaExtensions

最近,在 Github 上面发现了这一个框架,它也可以帮助我们解决 RxJava 异常过程中信息不全的问题。它的基本使用如下:

使用

https://github.com/akarnokd/RxJavaExtensions

第一步,引入依赖库

1dependencies {
2    implementation "com.github.akarnokd:rxjava2-extensions:0.20.10"
3}

第二步:先启用错误追踪:

1RxJavaAssemblyTracking.enable();

第三步:在抛出异常的异常,打印堆栈

 1    /**
 2     * 设置全局的 onErrorHandler。
 3     */
 4    fun setRxOnErrorHandler() {
 5        RxJavaPlugins.setErrorHandler { throwable: Throwable ->
 6            val assembled = RxJavaAssemblyException.find(throwable)
 7            if (assembled != null) {
 8                Log.e(TAG, assembled.stacktrace())
 9        }
10            throwable.printStackTrace()
11            Log.e(TAG, "setRxOnErrorHandler: throwable is $throwable")
12        }
13        }

原理

RxJavaAssemblyTracking.enable();

 1public static void enable() {
 2    if (lock.compareAndSet(false, true)) {
 3
 4        // 省略了若干方法
 5
 6        RxJavaPlugins.setOnObservableAssembly(new Function<Observable, Observable>() {
 7            @Override
 8            public Observable apply(Observable f) throws Exception {
 9                if (f instanceof Callable) {
10                    if (f instanceof ScalarCallable) {
11                        return new ObservableOnAssemblyScalarCallable(f);
12                    }
13                    return new ObservableOnAssemblyCallable(f);
14                }
15                return new ObservableOnAssembly(f);
16            }
17        });
18
19
20        lock.set(false);
21    }
22    }

可以看到,它调用了 RxJavaPlugins.setOnObservableAssembly 方法,设置了 RxJavaPlugins onObservableAssembly 变量

而我们上面提到的 Observable#fromCallable 方法,它里面会调用 RxJavaPlugins.onAssembly 方法,当我们的 onObservableAssembly 不为 null 的时候,会调用 apply 方法进行转换。

 1     public static <T> Observable<T> fromCallable(Callable<? extends T> supplier) {
 2    ObjectHelper.requireNonNull(supplier, "supplier is null");
 3    return RxJavaPlugins.onAssembly(new ObservableFromCallable<T>(supplier));
 4    }
 5    public static <T> Observable<T> onAssembly(@NonNull Observable<T> source) {
 6    Function<? super Observable, ? extends Observable> f = onObservableAssembly;
 7    if (f != null) {
 8        return apply(f, source);
 9    }
10    return source;
11    }

因此,即当我们设置了 RxJavaAssemblyTracking.enable(), Observable#fromCallable 传递进来的 supplier,最终会包裹一层,可能是 ObservableOnAssemblyScalarCallable,ObservableOnAssemblyCallable,ObservableOnAssembly。典型的装饰者模式应用,这里不得不说,RxJava 对外提供的这个点,设计得真巧妙,可以很方便我们做一些 hook。

我们就以 ObservableOnAssemblyCallable 看一下

 1   final class ObservableOnAssemblyCallable<T> extends Observable<T> implements Callable<T> {
 2
 3    final ObservableSource<T> source;
 4
 5    // 将在哪里创建的 Callable 的堆栈信息保存下来
 6    final RxJavaAssemblyException assembled;
 7
 8    ObservableOnAssemblyCallable(ObservableSource<T> source) {
 9        this.source = source;
10        this.assembled = new RxJavaAssemblyException();
11    }
12
13    @Override
14    protected void subscribeActual(Observer<? super T> observer) {
15        source.subscribe(new OnAssemblyObserver<T>(observer, assembled));
16    }
17
18    @SuppressWarnings("unchecked")
19    @Override
20    public T call() throws Exception {
21        try {
22            return ((Callable<T>)source).call();
23        } catch (Exception ex) {
24            Exceptions.throwIfFatal(ex);
25            throw (Exception)assembled.appendLast(ex);
26    }
27    }
28    }
29
30   public final class RxJavaAssemblyException extends RuntimeException {
31
32    private static final long serialVersionUID = -6757520270386306081L;
33
34    final String stacktrace;
35
36    public RxJavaAssemblyException() {
37        this.stacktrace = buildStackTrace();
38    }
39    }

可以看到,他是直接在 ObservableOnAssemblyCallable 的构造方法的时候,直接将 Callable 的堆栈信息保存下来,类为 RxJavaAssemblyException。

而当 error 报错的时候,调用 RxJavaAssemblyException.find(throwable) 方式,判断是不是 RxJavaAssemblyException,是的话,直接返回。

 1    public static RxJavaAssemblyException find(Throwable ex) {
 2    Set<Throwable> memory = new HashSet<Throwable>();
 3    while (ex != null) {
 4        if (ex instanceof RxJavaAssemblyException) {
 5            return (RxJavaAssemblyException)ex;
 6        }
 7
 8        if (memory.add(ex)) {
 9            ex = ex.getCause();
10        } else {
11            return null;
12    }
13    }
14    return null;
15    }

到这里,RxJavaAssemblyTracking 能将 error 信息完整打印出来的流程已经讲明白了,其实就是在创建 Callable 的时候,采用一个包装类,在构造函数的时候,将 error 信息报错下来,等到出错的时候,再将 error 信息,替换成保存下来的 error信息。

我们的自定义 Hook 也是利用这种思路,提前将 callable 创建的堆栈暴露下来,换汤不换药。

一些思考

上述的方案我们一般不会带到线上,为什么呢?因为对于每一个 callable,我们需要提前保存堆栈,而获取堆栈是耗时的。那有没有什么方法呢?

如果项目有接入 Matrix 的话,可以考虑借用 Matrix trace 的思想,因为在方法前后插入 AppMethodBeat#i 和 AppMethodBeat#o 这样当我们执行方法的时候,因为插桩了,我们可以方便得获取到方法执行耗时,以及方法的调用栈。

1// 第一步:需要在合适的实际先生成 beginRecord
2AppMethodBeat.IndexRecord  beginRecord = AppMethodBeat.getInstance().maskIndex("AnrTracer#dispatchBegin");
3// 第二步:方法的调用栈信息在 data 里面
4 long[] data = AppMethodBeat.getInstance().copyData(beginRecord);
5第三步:
6将 data 转化为我们想要的 stack(初步看了代码,需要我们修改 trace 的代码)

github:https://github.com/gdutxiaoxu/HookDemo

参考资料
rxjava-2-doesnt-tell-the-error-line
how-to-log-a-stacktrace-of-all-exceptions-of-rxjava2

最后

喜欢的小伙伴别忘了点赞收藏加关注呀~

在没有实验数据的情况下,如何高效快速发表高影响因子论文 最新基于Citespace、vosviewer、R语言的文献计量学可视化分析技术及全流程文献可视化SCI论文高效写作方法 阅读详情

相关推荐

从打印攻击到视频重放:手把手用OULU-NPU训练你的第一个活体检测模型

本文详细介绍了如何使用OULU-NPU数据集训练活体检测模型,以应对打印攻击和视频重放等安全威胁。通过PyTorch框架,从环境准备、数据加载、预处理到模型架构设计,手把手教你构建一个高效的双流网络,结合CNN和LSTM技术,提升模型在多种攻击场景下的检测准确率。

weixin_29092031的博客 386

rxjava 错误处理_RxJava的默认错误处理

rxjava 错误处理When working with RxJava, you’ll sooner or later end up dealing with this exception: 使用RxJava时 ,您迟早会遇到以下异常: io.reactivex.exceptions.OnErrorNotImplementedException: The exception was not ha...

weixin_26739079的博客 1813

CST高阶技巧:用周期性边界快速仿真共面波导色散特性(含JDM求解器优化)

本文详细介绍了在CST仿真软件中,利用周期性边界条件结合JDM本征模求解器,高效分析共面波导色散特性的高阶技巧。该方法通过仿真一个单元胞而非整条传输线,大幅提升计算效率,并提供了从建模、边界设置、求解器优化到后处理的完整工作流程,是高频电路设计的实用指南。

weixin_29280219的博客 403

io.reactivex.exceptions.OnErrorNotImplementedException

实体类中 int 类型默认不设值也是0;使用 Integer 就不会有这种问题。WakaTime致力于为每位程序员提供全自动的时间跟踪功能。

chengzhenjia的博客 654

【工具】GitHub学生认证+PyCharm配置Copilot全流程指南

本文提供了一份详细的GitHub学生认证及在PyCharm中配置Copilot的完整指南。通过完成A2F认证、准备有效材料并使用干净网络环境,学生可免费获取GitHub Copilot Pro订阅,极大提升编程学习与开发效率。

w7x8y9z的博客 1459

Realsense D435i运行ORB-SLAM3

【代码】Realsense D435i运行ORB-SLAM3。

MAX_Hope的博客 2563

The exception was not handled due to missing onError handler in the subscribe() method call

在自定义Application的onCreate方法中加入。2、使用subscribe的下面构造方法捕获异常。1、全局捕获rxjava异常。

chuyouyinghe的专栏 3334

Springboot——接入企业微信聊天机器人

最近企业微信的聊天机器人很火也很好玩,本期想自己接入一个玩玩试试水,同时也接入AI大模型进行数据的交互。

专注写bug 1328

RxJava2 堆栈信息显示不全解决方案

本文首发我的博客,github 地址 文章目录现象第一种方案,自定义 Hook 解决RxJavaExtensions使用原理一些思考参考资料推荐阅读 现象 大家好,我是徐公,今天为大家带来的是 RxJava 的一个血案,一行代码 return null 引发的。 前阵子,组内的同事反馈说 RxJava 在 debug 包 crash 了,捕获到的异常信息不全。(即我们捕获到的堆栈没有包含我们自己代码,都是一些系统或者 RxJava 框架的代码) 典型的一些 error 信息如下: io.reactiv.

徐公,微信公众号同名 1700

ANSYS Fluent:湍流模型理论与应用

雷诺平均方程(RANS,Reynolds-Averaged Navier-Stokes equations)是湍流建模中最常用的方法。它通过将Navier-Stokes方程中的瞬时速度分解为平均速度和脉动速度,然后对这些方程进行时间平均,从而简化了湍流的计算。RANS方法的关键在于湍流闭合问题的解决,即如何准确地表示脉动速度的统计量。雷诺应力模型(RSM)是一种更高级的湍流模型,它通过求解六个雷诺应力方程来描述湍流的各向异性。RSM模型能够更准确地预测复杂的湍流流动,如旋转流和分离流,但计算成本较高。

kkchenjj的博客 2947

csp信奥赛C++标准模板库STL案例应用1

csp信奥赛C++标准模板库STL案例应用1

王老师青少年编程 1383

io.reactivex.exceptions.OnErrorNotImplementedException: The mapper function returned a null value.

RxJavaPlugins.setErrorHandler(new Consumer&lt;Throwable&gt;() { @Override public void accept(Throwable throwable) { //异常处理 Log.d("onRxJavaErrorHandler",throwable+""); } }...

清晨码农的专栏 1万+

Win10 系统下VisualStudio2022 配置点云库 PCL1.13.0

Win10 系统下VisualStudio2022 配置点云库 PCL1.13.0与Win10 系统下 VisualStudio2019 配置点云库 PCL1.11.1流程基本相同,主要区别有两点: * 从PCL1.12.0版本开始需要进行`启用增强指令集`的设置。 * 附加依赖项添加的内容不同。

点云侠的博客 7006

RxJava 异常时堆栈显示不正确?解决方法都在这里

首先,我们先来想一下,什么是堆栈?在我的理解里面,堆栈是用来储存我们程序当前执行的信息。在 Java 当中,我们通过可以拿到当前线程的堆栈信息,注意是当前线程的堆栈。而 RxJava 抛出异常的地方,是在执行 Callable#call 方法中,它打印的自然是的方法调用栈,而如果 Callable#call 的调用线程跟 callable 的创建线程不一致,那肯定拿不到 创建 callable 时候的堆栈。

IT徐师兄 808

OV9734 DATASHEET,完整规格书

OV9734完整规格书,包括电气参数,尺寸规格,寄存器配置表等

蓝牙模块HM-10手册

蓝牙模块HM-10手册,该手册对蓝牙模块HM-10进行了详细的介绍和使用方法以及一些AT指令。

开源项目分析:RxJava2Debug的架构设计与代码组织

RxJava2Debug是一个为RxJava 2.x提供有意义堆栈跟踪的扩展库,它通过增强异常信息来帮助开发者快速定位异步代码中的问题。本文将深入剖析该项目的架构设计与代码组织,揭示其如何实现堆栈跟踪优化这一核心功能。 ## 项目整体架构概览 RxJava2Debug采用典型的Java库项目结构,主要包含两大模块:核心功能模块`rxjava2debug`和示例应用模块`example-andr

gitblog_00390的博客 470

文档:亲测可用解决vnc灰屏,黑屏,鼠标大黑叉情况

主要解决vnc-viewer灰屏,黑屏,鼠标大黑叉等现象,详细见文档。

Stacktrace-decoroutinator:恢复Kotlin协程异常堆栈的利器

Stacktrace-decoroutinator:恢复Kotlin协程异常堆栈的利器 项目介绍 在Kotlin开发中,协程(Coroutines)是一个强大的特性,它允许开发者以同步的方式编写异步代码,极大地简化了并发编程的复杂性。然而,当协程中抛出异常时,堆栈跟踪信息往往会被截断,导致调试过程变得异常困难。为了解决这一问题,Stacktrace-decoroutinator应运而生。 Stac...

gitblog_00070的博客 370

Camera2Demo

在Camera2 的基础上进行封装,使得Camera2一堆初始化逻辑与Activity分离,降低耦合度,完成预览拍照并保存的操作

安卓开发中遇到的奇奇怪怪的问题(三)

https://github.com/dstmath/HWFramework/blob/master/Honor5C-7.0/src/main/java/java/lang/Daemons.java https://github.com/dstmath/HWFramework/blob/master/P9-8.0/src/main/java/java/lang/Daemons.java https...

唯鹿的博客 8325

深入解析Java空指针异常:从JVM原理到Android实战预防

在Java编程中,空指针异常(NullPointerException)是常见的运行时错误,其本质是试图在值为null的对象引用上调用方法。从JVM视角看,当引用变量存储null值时,表示未指向任何堆内存对象,此时进行动态绑定和方法调用就会触发异常。这一机制虽然简单,却深刻反映了代码健壮性和设计严谨性问题。在工程实践中,空指针异常的高发场景包括未初始化变量、方法返回null、集合操作和链式调用等,尤其在Android开发中,生命周期管理和异步回调更易引发此类问题。通过理解JVM原理、掌握排查流程、采用Opt

weixin_30367169的博客 393

今年安卓开发中碰到的几个稀奇古怪的问题

如果你也遇到了,请保持淡定~ 1.SIGBUS和SIGSEGV 首先是这两个名词的说明: SIGBUS(Bus error)意味着指针所对应的地址是有效地址,但总线不能正常使用该指针。通常是未对齐的数据访问所致。 SIGSEGV(Segment fault)意...

weixin_34085658的博客 153

Android开发中空指针异常(NPE)的深度解析与系统化防御策略

空指针异常(NullPointerException)是Java和Kotlin开发中最常见的运行时异常之一,其本质是程序试图通过一个值为null的对象引用调用方法或访问属性。从技术原理看,Java虚拟机在执行方法调用前会强制进行空值检查,当发现接收者对象引用为null时立即抛出异常。这一机制虽然保证了类型安全,但也成为代码健壮性的重要挑战。在Android开发实践中,空指针异常常出现在对象未初始化、异步回调与生命周期不同步、集合访问等高频场景。通过Kotlin的空安全特性、契约式编程、依赖注入规范等系统性防

weixin_34220179的博客 370

解决Bug:OnErrorNotImplementedException

文 | Promise Sun 一、Bug问题描述 在运行app项目时报错: io.reactivex.exceptions.OnErrorNotImplementedException: CLEARTEXT communication to baobab.kaiyanapp.com not permitted by network security policy 报异常如下图: 二、解决方案 1.在res目录下新建xml目录,然后创建network_security_config..

Promise Sun special column 1319

解决 Retrofit io.reactivex.exceptions.OnErrorNotImplementedException: HTTP 404 Not Found

io.reactivex.exceptions.OnErrorNotImplementedException: HTTP 404 Not Found         at io.reactivex.internal.functions.Functions$14.accept(Functions.java:229)         at io.reactivex.internal.functio...

Alex老夫子的专栏 1万+

RxJava OnErrorNotImplementedException 的处理

RxJavaPlugins.setErrorHandler(new Consumer<Throwable>() { @Override public void accept(Throwable throwable) { //异常处理 } }); 对于上面这个错...

weixin_41673515的博客 4556

一次RxJava2导致的线上崩溃问题:The exception was not handled due to missing onError handler in the subscribe()

周末正在休(玩)息(LOL),突然产品告诉我线上崩溃率很高,还记得周五测试很忙,没怎么测产品就急着上线了。 吓得我感觉看了下友盟数据,发现错误频次最高的是一个网络请求无法解析域名的异常: 第一反应:国外用户无法解析我们配置后台数据的域名,但是理论上来说也应该是网络错误,而不是闪退呀。 第二反应:看到错误的抛出地址是 io.reactivex.internal.functions.Fun...

tian2342的专栏 1万+

Rxjava的OnErrorNotImplementedException异常分析

通过名字我们可以发现这个是因为onError没有实现导致的异常,那么为什么不实现onError会这样呢 这里写了两个demo方法: 使用Observer做为订阅者 使用Consumer做为订阅者 二者都在onNext函数中进行了异常的抛出。 第一种方式可以正常的回调onError 并打印信息 第二种方式直接崩溃-----堆栈信息中正是OnErrorNotImplementedException Consumer是Observer的简化版 上面的demo我...

qijingwang的博客 3642
上一篇: Java之戳中痛点之 synchronized 深度解析
下一篇: 致Android开发工程师:过了笔试,千万别栽在自己最擅长得技术面试上——70道Android技术面试题分享
不秃头de程序猿
博客等级 码龄5年 4089粉丝 1478原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值