基于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
相关产品推荐
相关产品推荐

