You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

RxJava中onErrorResumeNext与onError异常问题排查与解决

解析启动时断网触发CompositeException的原因

先聊聊你的场景:用Retrofit+RxJava做网络请求,Realm做本地缓存,预期请求失败时自动从缓存读取数据。测试发现先成功请求过再断网时,onErrorResumeNext能正常兜底加载缓存;但启动App就开飞行模式,请求直接走到onError回调,日志报CompositeException(包含2个异常)。你把Realm.init(getContext())移到请求调用前就解决了问题,咱们来拆解下背后的原因。

核心问题:Realm初始化的时机错配

首先得明确Realm的规则:必须在第一次调用Realm.getDefaultInstance()之前完成Realm.init()初始化,而且这个初始化最好全局一次性完成,比如在Application的onCreate里。

咱们来看你原来的代码逻辑:

apiContent.getNews("Token " + myHelper.getAuthToken(getActivity()))
    .subscribeOn(Schedulers.io())
    .observeOn(AndroidSchedulers.mainThread())
    .map(NewsObject::getResults)
    .flatMap(news -> {
        // 只有请求成功时,才会执行到这里初始化Realm
        Realm.init(getContext());
        Realm.getDefaultInstance().executeTransaction(realm -> {
            realm.delete(News.class);
            realm.insert(news);
            Log.d("myLogs", "Cached");
        });
        return Observable.just(news);
    })
    .onErrorResumeNext(throwable -> {
        // 请求失败时直接走到这里,尝试获取Realm实例
        Realm realm = Realm.getDefaultInstance();
        RealmResults<News> results = realm.where(News.class).findAll();
        ArrayList<News> dataNews = new ArrayList<News>();
        dataNews.addAll(realm.copyFromRealm(results));
        Log.d("myLogs", "Error, loading from cache");
        return Observable.just(dataNews);
    })
    // ...subscribe回调省略

两种场景的差异

  1. 先成功请求再断网:

    • 第一次请求成功,flatMap执行,Realm.init()完成初始化。
    • 之后断网请求失败,进入onErrorResumeNext时,Realm已经初始化过了,能正常获取实例、读取缓存,不会额外抛出异常,onErrorResumeNext正常兜底。
  2. 启动就开飞行模式:

    • 网络请求直接失败,上游Observable直接发射error信号,flatMap里的代码根本不会执行,也就是说Realm.init()完全没被调用过。
    • 进入onErrorResumeNext后,调用Realm.getDefaultInstance(),这时候Realm还没初始化,会抛出IllegalStateException(提示Realm未初始化)。
    • 原来的网络异常 + 这个Realm未初始化的异常,被RxJava包装成了CompositeException,最终走到onError回调,而非onErrorResumeNext正常返回缓存。

为什么移到请求前就解决了?

把Realm.init(getContext())移到请求调用前,相当于不管请求成功还是失败,Realm都已经完成初始化。当启动就断网时,onErrorResumeNext里调用Realm.getDefaultInstance()不会抛出异常,只会处理原来的网络异常,顺利读取缓存返回,自然不会出现CompositeException。

额外建议:Realm初始化的最佳实践

最好把Realm.init()放在自定义Application的onCreate方法里,全局初始化一次:

public class MyApp extends Application {
    @Override
    public void onCreate() {
        super.onCreate();
        Realm.init(this);
        // 还可以在这里配置Realm全局规则,比如加密、数据迁移等
        RealmConfiguration config = new RealmConfiguration.Builder().build();
        Realm.setDefaultConfiguration(config);
    }
}

这样整个App里任何地方用Realm都不用重复初始化,从根源避免这类初始化时机的问题。

内容的提问来源于stack exchange,提问作者Vitaly Kalenik

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.15 06:43:39