确认需求
- 打开App,请求数据时先检查缓存数据是否需要迁移,如果有缓存数据升级,那么就删除原有的缓存数据。
- 如果有缓存数据,判断数据是否过期,如果过期则网络请求,如果没有过期,则返回缓存数据。
- 如果网络请求成功,返回数据,同时更新缓存信息
- 如果网络请求失败,返回缓存信息。
- 如果网络失败,缓存为空,则返回空数据或者抛出异常信息
改动点
- 每次读取数据之后都会处理过期数据,不满足要求4
- 先读缓存,再网络加载
/core/internal/cache/RetrieveRecord.java
<T> Record<T> retrieveRecord(String providerKey, String dynamicKey, String dynamicKeyGroup,
boolean useExpiredDataIfLoaderNotAvailable, Long lifeTime, boolean isEncrypted) {
String composedKey = composeKey(providerKey, dynamicKey, dynamicKeyGroup);
Record<T> record = memory.getIfPresent(composedKey);
if (record != null) {
record.setSource(Source.MEMORY);
} else {
try {
record = persistence.retrieveRecord(composedKey, isEncrypted, encryptKey);
record.setSource(Source.PERSISTENCE);
memory.put(composedKey, record);
} catch (Exception ignore) {
return null;
}
}
record.setLifeTime(lifeTime);
// 删除缓存过期的逻辑
// if (hasRecordExpired.hasRecordExpired(record)) {
// if (!dynamicKeyGroup.isEmpty()) {
// evictRecord.evictRecordMatchingDynamicKeyGroup(providerKey, dynamicKey,
// dynamicKeyGroup);
// } else if (!dynamicKey.isEmpty()) {
// evictRecord.evictRecordsMatchingDynamicKey(providerKey, dynamicKey);
// } else {
// evictRecord.evictRecordsMatchingProviderKey(providerKey);
// }
//
// return useExpiredDataIfLoaderNotAvailable ? record : null;
// }
return record;
}
- 在请求前,会判断是否过期,同时处理所有过期数据
/core/internal/ProcessorProvidersBehaviour
private Observable<Integer> startProcesses(
io.rx_cache2.internal.migration.DoMigrations doMigrations,
final io.rx_cache2.internal.cache.EvictExpiredRecordsPersistence evictExpiredRecordsPersistence) {
// 处理迁移数据,我们只需要处理迁移就好
Observable<Integer> oProcesses = doMigrations.react().flatMap(new Function<Integer, ObservableSource<Integer>>() {
@Override public ObservableSource<Integer> apply(Integer ignore) throws Exception {
// 删除所有过期数据,注释这段逻辑
return evictExpiredRecordsPersistence.startEvictingExpiredRecords();
}
}).subscribeOn((Schedulers.io())).observeOn(Schedulers.io()).share();
oProcesses.subscribe(new Consumer<Integer>() {
@Override public void accept(Integer ignore) throws Exception {
hasProcessesEnded = true;
}
});
return oProcesses;
}
- 在缓存过期之后,网络请求失败的同时,依然会处理过期数据
/core/internal/ProcessorProvidersBehaviour
private Observable<Reply> getDataFromLoader(final io.rx_cache2.ConfigProvider configProvider,
final Record record)
...
.onErrorReturn(new Function<Object, Object>() {
@Override public Object apply(Object o) throws Exception {
如果网络错误,会判断这个 provider 的数据是否过期,如果过期,就删除掉
// clearKeyIfNeeded(configProvider);
boolean useExpiredData = configProvider.useExpiredDataIfNotLoaderAvailable() != null ?
configProvider.useExpiredDataIfNotLoaderAvailable()
: useExpiredDataIfLoaderNotAvailable;
if (useExpiredData && record != null) {
return new Reply(record.getData(), record.getSource(), configProvider.isEncrypted());
}
throw new io.rx_cache2.RxCacheException(io.rx_cache2.internal.Locale.NOT_DATA_RETURN_WHEN_CALLING_OBSERVABLE_LOADER
+ " "
+ configProvider.getProviderKey(), (Throwable) o);
}
});
- 数据迁移过程的bug, 如果缓存为空
/internal/migration/DeleteRecordMatchingClassName.java
private boolean evictRecord(io.rx_cache2.internal.Record record) {
没有判断 record 为空的情况。
//if(record == null) return false;
String candidate = record.getDataClassName();
for (Class aClass : classes) {
String className = aClass.getName();
if (className.equals(candidate)) {
return true;
}
}
return false;
}
- 一些小改动,小判断
//VisibleForTesting
<T> Observable<T> getData(final io.rx_cache2.ConfigProvider configProvider) {
Record<Object> record = twoLayersCache.retrieve(configProvider.getProviderKey(), configProvider.getDynamicKey(),
configProvider.getDynamicKeyGroup(), useExpiredDataIfLoaderNotAvailable,
configProvider.getLifeTimeMillis(), configProvider.isEncrypted());
Observable<Reply> replyObservable;
Observable<Reply> remoteObservable = getDataFromLoader(configProvider, record);
if(record == null) {
// only load from network
replyObservable = remoteObservable;
} else {
Observable<Reply> localObservable = Observable.just(new Reply(record.getData(), record.getSource(), configProvider.isEncrypted()));
if(!evictExpiredRecordsPersistence.isExpired(record) && !configProvider.evictProvider().evict()) {
replyObservable = localObservable;
} else {
replyObservable = Observable.concat(localObservable, remoteObservable);
}
}
return (Observable<T>) replyObservable.map(new Function<Reply, Object>() {
@Override public Object apply(Reply reply) throws Exception {
return ProcessorProvidersBehaviour.this.getReturnType(configProvider, reply);
}
});
}
最后更换依赖
1. Fork代码,修改代码,创建tag,发布到jitpack.io, 客户端更换依赖就好了
2. implementation 'com.github.weixuefeng.RxCache-1:runtime:1.8.7-3x'
感谢
- 你不知道的Retrofit缓存库RxCache JessYan 的介绍。
- RxCache GitHub 链接
- RxCache源码分析
原文链接
- 原文链接