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

基于Retrofit与RxAndroid的时间戳校验逻辑实现是否正确?

你的Retrofit+RxAndroid实现存在几个关键问题,我来帮你梳理并修正

先直接点明原代码里的核心问题:

  • 返回null会导致崩溃:在flatMap里返回null是RxJava严格禁止的,这会直接抛出NullPointerException,因为ObservableSource不能为null。
  • 未处理本地数据库读取场景:当时间戳没有变化时,你需要从Realm读取本地的Infraction数据并包装成Observable返回,而不是直接返回null。
  • 线程调度不合理:subscribeOn(Schedulers.newThread())不如Schedulers.io()适合IO操作(网络、数据库);另外你在创建Observable前直接查询Realm,若在主线程执行虽Realm允许,但更规范的做法是把数据库查询放到IO线程。
  • 缺少本地TimeStamps更新:获取到新的TimeStamps后没有同步到本地Realm,下次对比还是旧数据,逻辑完全失效。
  • 空指针风险:如果是首次启动,Realm里还没有TimeStamps数据,stamps.getInfractionTimeStamps()会直接触发空指针。

修正后的完整实现

// 1. 从Realm读取本地TimeStamps,放到IO线程执行保证线程安全
Observable<TimeStamps> localTimeStampObservable = Observable.fromCallable(() -> {
    try (Realm realm = Realm.getDefaultInstance()) {
        return realm.copyFromRealm(realm.where(TimeStamps.class).findFirst());
    }
}).subscribeOn(Schedulers.io());

// 2. 发起网络请求获取最新TimeStamps,同时更新到本地Realm
Observable<TimeStamps> remoteTimeStampObservable = apiInterface.getTimeStamp()
        .subscribeOn(Schedulers.io())
        .doOnNext(remoteStamps -> {
            try (Realm realm = Realm.getDefaultInstance()) {
                realm.executeTransaction(r -> {
                    r.copyToRealmOrUpdate(remoteStamps);
                });
            }
        });

// 3. 合并本地与远程TimeStamps,判断是否需要拉取新的Infraction
Observable.combineLatest(localTimeStampObservable, remoteTimeStampObservable, (localStamps, remoteStamps) -> {
    // 处理首次启动本地无数据的情况,直接拉取远程数据
    if (localStamps == null) {
        return true;
    }
    // 对比时间戳是否发生变化
    return !remoteStamps.getInfractionTimeStamps().equalsIgnoreCase(localStamps.getInfractionTimeStamps());
})
.flatMap(needFetchRemote -> {
    if (needFetchRemote) {
        // 时间戳变化,拉取远程Infraction并同步到本地
        return apiInterface.getInfractions()
                .subscribeOn(Schedulers.io())
                .doOnNext(infractions -> {
                    try (Realm realm = Realm.getDefaultInstance()) {
                        realm.executeTransaction(r -> {
                            r.delete(Infraction.class);
                            r.copyToRealmOrUpdate(infractions);
                        });
                    }
                });
    } else {
        // 时间戳未变化,从本地Realm读取数据
        return Observable.fromCallable(() -> {
            try (Realm realm = Realm.getDefaultInstance()) {
                return realm.copyFromRealm(realm.where(Infraction.class).findAll());
            }
        }).subscribeOn(Schedulers.io());
    }
})
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Observer<List<Infraction>>() {
    @Override
    public void onSubscribe(Disposable d) {
        // 建议在这里把Disposable加入CompositeDisposable管理,避免内存泄漏
    }

    @Override
    public void onNext(List<Infraction> infractions) {
        // 在这里更新UI展示数据
    }

    @Override
    public void onError(Throwable e) {
        // 统一处理异常:网络失败、数据库操作失败等
        Log.e("InfractionFetch", "获取数据失败", e);
    }

    @Override
    public void onComplete() {
        // 操作完成的回调(可选)
    }
});

关键改进点说明

  • 彻底避免空指针:所有分支都返回有效的Observable,不会出现null场景。
  • 线程安全的Realm操作:用try-with-resources自动管理Realm实例,所有数据库操作都放到IO线程,避免主线程阻塞。
  • 覆盖首次启动场景:当本地无TimeStamps数据时,直接拉取远程最新数据。
  • 自动同步本地数据:获取到新的TimeStamps和Infraction后,自动同步到Realm,保证后续对比的准确性。
  • 规范的线程调度:网络和数据库操作都用IO线程,UI更新用主线程,完全符合Android线程规范。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.15 07:51:13