RxJava实现缓存过期逻辑:Realm取数/超时从Api拉取(新手求助)
嘿,刚接触RxJava的话,这种「缓存优先+过期刷新」的场景其实是RxJava最擅长处理的典型案例之一!我给你拆解清楚实现思路和具体代码,保证你能快速上手~
核心思路拆解
我们的目标是:
- 先从Realm里读取缓存数据,判断是否在5分钟有效期内
- 如果缓存有效,直接返回缓存数据给Presenter
- 如果缓存过期/不存在,就调用API拉取新数据,保存到Realm后再返回给Presenter
用RxJava的操作符可以把这些逻辑串联得非常流畅,核心是用concat+firstElement来优先取缓存,缓存无效时自动 fallback 到API请求。
具体代码实现
第一步:定义带缓存时间的Realm实体类
首先给你的数据模型加一个lastUpdated字段,用来记录最后一次从API拉取数据的时间:
public class YourDataModel extends RealmObject { @PrimaryKey private String uniqueId; // 必须有主键,方便后续更新缓存 // 你的其他数据字段 private String content; private Date lastUpdated; // 缓存时间戳 // Getter & Setter 方法 public Date getLastUpdated() { return lastUpdated; } public void setLastUpdated(Date lastUpdated) { this.lastUpdated = lastUpdated; } }
第二步:实现数据仓库(Repository)核心逻辑
这部分是整个流程的核心,我们把缓存判断、API请求、Realm操作都封装在这里:
public class DataRepository { private final YourApiService apiService; // 你的API请求服务,比如Retrofit创建的实例 public DataRepository(YourApiService apiService) { this.apiService = apiService; } // 判断缓存是否在5分钟有效期内 private boolean isCacheValid(YourDataModel cachedData) { if (cachedData == null) return false; long currentTime = System.currentTimeMillis(); long cacheTimestamp = cachedData.getLastUpdated().getTime(); // 5分钟 = 5*60*1000毫秒 return (currentTime - cacheTimestamp) < 300000; } // 对外暴露的获取数据方法,返回Observable public Observable<YourDataModel> getData() { // 1. 构建缓存Observable:从Realm读取并过滤有效缓存 Observable<YourDataModel> cacheObservable = Observable.fromCallable(() -> { Realm realm = Realm.getDefaultInstance(); try { // 读取缓存并拷贝到非Realm对象(避免跨线程问题) return realm.copyFromRealm(realm.where(YourDataModel.class).findFirst()); } finally { realm.close(); // 务必关闭Realm实例 } }).filter(this::isCacheValid); // 只保留有效缓存 // 2. 构建API Observable:请求数据并保存到Realm Observable<YourDataModel> apiObservable = apiService.fetchDataFromApi() // 假设这个方法返回Observable<YourDataModel> .flatMap(apiData -> { // 把API返回的数据保存到Realm return Observable.fromCallable(() -> { Realm realm = Realm.getDefaultInstance(); try { realm.executeTransaction(r -> { apiData.setLastUpdated(new Date()); // 设置当前时间为缓存时间 r.copyToRealmOrUpdate(apiData); // 保存或更新数据 }); return apiData; } finally { realm.close(); } }); }); // 3. 串联逻辑:先试缓存,缓存无效就走API,取第一个有效结果 return Observable.concat(cacheObservable, apiObservable) .firstElement() // 只要第一个有效的数据源 .toObservable(); } }
第三步:Presenter层调用
在Presenter里调用Repository的方法,处理线程调度和结果回调:
public class YourPresenter { private final DataRepository repository; private final YourView view; // 你的View接口,用于更新UI public YourPresenter(DataRepository repository, YourView view) { this.repository = repository; this.view = view; } public void loadData() { repository.getData() .subscribeOn(Schedulers.io()) // 耗时操作(Realm/API)放到IO线程 .observeOn(AndroidSchedulers.mainThread()) // 结果回调到主线程更新UI .subscribe( data -> view.showSuccessData(data), // 成功拿到数据,更新UI error -> view.showError(error.getMessage()) // 处理请求失败 ); } }
关键要点提醒
- Realm线程安全:Realm实例不能跨线程使用,所以每次操作都要在当前线程创建并关闭,这里用
Observable.fromCallable把同步的Realm操作包装成Observable,方便线程调度。 - 线程调度必加:一定要用
subscribeOn把IO操作放到后台线程,observeOn切回主线程,否则会阻塞UI。 - 错误处理兜底:如果API请求失败,可以给
apiObservable加onErrorResumeNext,比如返回过期的缓存作为兜底:apiObservable = apiService.fetchDataFromApi() .flatMap(...) .onErrorResumeNext(throwable -> { // 这里可以返回过期缓存 return Observable.fromCallable(() -> { Realm realm = Realm.getDefaultInstance(); try { return realm.copyFromRealm(realm.where(YourDataModel.class).findFirst()); } finally { realm.close(); } }).filter(Objects::nonNull); // 确保缓存不为空 }); - 缓存时间计算:注意时间单位是毫秒,别把5分钟算成5*60=300(秒),要转成300000毫秒。
刚开始用RxJava可能会觉得操作符有点绕,但多写几次这种场景,很快就能掌握它的链式思维啦!
内容的提问来源于stack exchange,提问作者DdM
相关产品推荐
相关产品推荐

