如何防止Rx订阅事件在onError()过程中奔溃

作者: 黄光华 | 来源:发表于2018-05-21 22:27 被阅读127次

起因

最近在应用检测平台上看到一些奔溃报告,貌似是RxJava相关的:


OnErrorFailedException.png

定位到了OnErrorFailedException,Google一下,


throw OnErrorFailedException.png

RxJava注释上说,这是onError()里的代码报异常。接触过RxJava的都应该知道,onError()是我们订阅事件时,中途出现问题时会回调的方法(onNext()中出现的异常也会回调onError())。如果连onError()里的代码也出现异常,那么Rx框架是会抛出这个OnErrorFailedException,程序就会奔溃。

按道理,此时应该在onError()里找出那行有毒的代码。尴尬的是,项目中基本在执行网络请求的地方都用了Rx订阅事件,少说也有二三百个地方用到了onError(),奔溃报告并没有记录具体出错的地方, 一个个地方排查无疑是效率低的做法。而且,下次再在onError()写出产生异常的代码那怎么办?毕竟没人能保证自己一定不会再犯错。我想到比较好的办法是为onError()统一捕获异常!!幸好,在实现Rx订阅事件的每个地方,之前我并没有直接用到Subscriber这个Rx提供的抽象类,而是自己做了个中间层,SubscriberAdapter。这为统一为onError()捕获异常提供了一个入口。

public abstract class SubscriberAdapter<T> extends Subscriber<T> {
    @Override
    public void onCompleted() {
    }

    @Override
    public void onNext(T t) {
        onSuccess(t);
    }

    public abstract void onSuccess(T t);

解决思路

在这之前,我只简单处理了下onNext(),目的是,日后如果想在onNext()前后统一添加动作(没理解错的话,这是设计模式中的装饰者模式?),那就很方便了。没想到现在首先要添加动作的是onError()。在项目中,每处订阅事件的地方都实现了SubscriberAdapter,也写死了方法名onError()。此时就算我们在SubscriberAdapter类里面怎么重写onError()也不会对影响到订阅事件发生的地方,也就无法捕捉异常,怎么办呢?这里提供一个小技巧,我们先在SubscriberAdapter类里重写onError(),但是空实现,

public abstract class SubscriberAdapter<T> extends Subscriber<T> {
    @Override
    public void onError() {
    }
}

此时,studio已经将这个空实现的方法和几百处具体实现的onError()关联上了。此时我们光标选中SubscriberAdapter的"onError"字符,同时按下shift+F6,就可以同时修改几百处方法名称,我在这改为onDispatchError()。然后我们再重写多一次onError(),这次就要捕捉异常了,具体代码是

public abstract class SubscriberAdapter<T> extends Subscriber<T> {
    @Override
    public void onCompleted() {
    }

    @Override
    public void onNext(T t) {
        onSuccess(t);
    }

    public abstract void onSuccess(T t);

    @Override
    public void onError(Throwable e) {
        try {
            onDispatchError(e);
        } catch (Exception exception) {
            Toast.makeText(IYourCarApplication.getAppContext(), "处理出现错误", Toast.LENGTH_LONG).show();
        }
    }

    public void onDispatchError(Throwable e) {
    }

好了,轻松为原来几百处实现了onError()接口的地方都统一捕捉了异常。现在就算在onError()里写了本来会导致奔溃的代码,现在也起码不会奔溃,给了用户提示,用户体验对比直接奔溃要好了不少。

效果演示,我在onNext()和onError()故意设置空指针异常后,


demo.png

可以看到,空指针后并没有奔溃,并且弹出了我们设置的toast。

后话

当引入大型的第三方框架时(例如Rx,retrofit,Glide),在项目代码和框架之间多加一层,不直接调用框架的API,是很有必要的。因为如果开源框架的API变动的时候,或者像本文这样,想统一添加一些操作的时候,如果没有中间这一层,那么就很可能要每个地方都要修改了,这种基础的框架,一改肯定就是一千几百处的修改了,这会是多么痛的领悟~~

相关文章

  • 如何防止Rx订阅事件在onError()过程中奔溃

    起因 最近在应用检测平台上看到一些奔溃报告,貌似是RxJava相关的: 定位到了OnErrorFailedExce...

  • valueForKeyPath 奔溃

    昨天产品反馈了一个奔溃事件, 因为是做职业教育的, 刚好奔溃在课程上, 因此这里做处理总结。 请问下面代码会奔溃吗...

  • RxJava 错误处理

    Rx中, 很容易处理异常, 整个链式调用过程中,如果异常不做处理, 最后都会交给onError; 不要过渡的依赖o...

  • 3.自定代理ip模块

    1.在爬虫中,频繁的访问目标服务器,可能会使服务器奔溃.网站为了防止非正常访问,造成服务器奔溃,一般会检测用户ip...

  • iOS Crash 文件分析,符号化

    在真机运行、苹果审核等过程中,App 可能出现奔溃。拿到的奔溃日志是如下图所示 这样是看不出问题出自哪里的。 解决...

  • RxJava2笔记(二、事件取消流程)

    在上一篇文章RxJava2笔记(一、事件订阅流程)中,我们讲解了RxJava的事件订阅流程,本文我们将继续讲解Rx...

  • iOS开发日志通过ftp上传的方法

    在开发过程中,需要收集奔溃日志,那怎么做到奔溃日志上传呢,通常集成第三方工具,什么友盟、蒲公英、腾讯之类的统计软件...

  • DYLD, Library not loaded: /usr/l

    奔溃日志 奔溃表现:iOS12.1 及以下启动奔溃奔溃日志: 解决方法:关闭bitcode,重新打包上传appst...

  • onerror事件

    定义和用法 onerror 事件会在文档或图像加载过程中发生错误时被触发。在装载文档或图像的过程中如果发生了错误,...

  • Debugging 操作

    可以Debug Rx代码的操作 debug 打印机出所有订阅,事件,和清除对象。 RxSwift.Resource...

网友评论

    本文标题:如何防止Rx订阅事件在onError()过程中奔溃

    本文链接:https://www.haomeiwen.com/subject/eimqjftx.html