RxJava全家桶中的缓存框架RxCache只有缓存时间的设置,并不能做到先加缓存后请求网络的功能,RxCache的基本使用,请看
1.认真的查看其源码之后,我们可以修改源码达到缓存功能;
RxCache的构建方式和Retrofit类似使用Builder构建
providers = new RxCache.Builder()
.persistence(cacheDir, new GsonSpeaker())
.using(Providers.class);
调用using,而using中使用的动态代理所有方法都会走InvocationHandler的invoke方法
public <T> T using(final Class<T> classProviders) {
proxyProviders = new ProxyProviders(builder, classProviders);
return (T) Proxy.newProxyInstance(
classProviders.getClassLoader(),
new Class<?>[] {classProviders},
proxyProviders);
}
相应的ProxyProviders的代理提供类在RxCache 1.5.2版本中使用的dagger2方式创建,ProxyProviders实现了InvocationHandler,所有的方法都会走invoke方法
@Override public Object invoke(final Object proxy, final Method method, final Object[] args)
throws Throwable {
return Observable.defer(new Func0<Observable<Object>>() {
@Override public Observable<Object> call() {
return processorProviders.process(proxyTranslator.processMethod(method, args));
}
});
}
先看看ProxyTranslator的processMethod方法
ConfigProvider processMethod(Method method, Object[] objectsMethod) {
ConfigProvider prev = loadConfigProviderMethod(method);
ConfigProvider configProvider = new ConfigProvider(prev.getProviderKey(),
null, prev.getLifeTimeMillis(), prev.requiredDetailedResponse(), prev.isExpirable(),
prev.isEncrypted(), getDynamicKey(method, objectsMethod),
getDynamicKeyGroup(method, objectsMethod),
getLoaderObservable(method, objectsMethod),
evictProvider(method, objectsMethod));
return configProvider;
}
传入方法和相应的参数,使用ConfigProvider 进行包装起来,并返回一个包装类ConfigProvider ,再回过头来看ProcessorProviders的process方法,点开一看是个接口,而对应的实现类是有dagger2生成的。查看RxCacheModule(管理RxCache中的注解注入参数的类)的provideProcessorProviders方法
@Provides ProcessorProviders provideProcessorProviders(
ProcessorProvidersBehaviour processorProvidersBehaviour) {
return processorProvidersBehaviour;
}
相应的实现类是ProcessorProvidersBehaviour 的process方法
@Override
public <T> Observable<T> process(final ConfigProvider configProvider) {
return (Observable<T>) Observable.defer(new Func0<Observable<Object>>() {
@Override public Observable<Object> call() {
if (hasProcessesEnded) {
return getData(configProvider);
}
return oProcesses.flatMap(new Func1<Void, Observable<?>>() {
@Override public Observable<?> call(Void aVoid) {
return getData(configProvider);
}
});
}
});
}
//VisibleForTesting
<T> Observable<T> getData(final ConfigProvider configProvider) {
return (Observable<T>) Observable.just(
twoLayersCache.retrieve(configProvider.getProviderKey(), configProvider.getDynamicKey(),
configProvider.getDynamicKeyGroup(), useExpiredDataIfLoaderNotAvailable,
configProvider.getLifeTimeMillis(), configProvider.isEncrypted()))
.map(new Func1<Record, Observable<Reply>>() {
@Override public Observable<Reply> call(final Record record) {
if (record != null && !configProvider.evictProvider().evict()) {
//如果是evict()为false增加缓存
return Observable.just(
new Reply(record.getData(), record.getSource(), configProvider.isEncrypted()));
}
//请求网络数据
return getDataFromLoader(configProvider, record);
}
}).flatMap(new Func1<Observable<Reply>, Observable<Object>>() {
@Override
public Observable<Object> call(Observable<Reply> responseObservable) {
return responseObservable.map(new Func1<Reply, Object>() {
@Override
public Object call(Reply reply) {
return getReturnType(configProvider, reply);
}
});
}
});
}
private Observable<Reply> getDataFromLoader(final ConfigProvider configProvider,
final Record record) {
return configProvider.getLoaderObservable().map(new Func1() {
@Override public Reply call(Object data) {
boolean useExpiredData = configProvider.useExpiredDataIfNotLoaderAvailable() != null ?
configProvider.useExpiredDataIfNotLoaderAvailable()
: useExpiredDataIfLoaderNotAvailable;
if (data == null && useExpiredData && record != null) {
return new Reply(record.getData(), record.getSource(), configProvider.isEncrypted());
}
//清除缓存数据
clearKeyIfNeeded(configProvider);
if (data == null) {
throw new RxCacheException(Locale.NOT_DATA_RETURN_WHEN_CALLING_OBSERVABLE_LOADER
+ " "
+ configProvider.getProviderKey());
}
//保存缓存数据
twoLayersCache.save(configProvider.getProviderKey(), configProvider.getDynamicKey(),
configProvider.getDynamicKeyGroup(), data, configProvider.getLifeTimeMillis(),
configProvider.isExpirable(), configProvider.isEncrypted());
return new Reply(data, Source.CLOUD, configProvider.isEncrypted());
}
}).onErrorReturn(new Func1() {
@Override public Object call(Object o) {
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 RxCacheException(Locale.NOT_DATA_RETURN_WHEN_CALLING_OBSERVABLE_LOADER
+ " "
+ configProvider.getProviderKey(), (Throwable) o);
}
});
}
Record记录的是缓存数据,缓存逻辑基本就在这个类里面TwoLayersCache的retrieve方法中
public <T> Record<T> retrieve(String providerKey, String dynamicKey, String dynamicKeyGroup,
boolean useExpiredDataIfLoaderNotAvailable, Long lifeTime, boolean isEncrypted) {
return retrieveRecord.retrieveRecord(providerKey, dynamicKey, dynamicKeyGroup,
useExpiredDataIfLoaderNotAvailable, lifeTime, isEncrypted);
}
其调用RetrieveRecord的retrieveRecord方法
<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 {
//SD卡中寻找,标记为sd卡数据
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;
}
源码解读依据这个解读的
- 修改源码,达到先读缓存后请求网络的功能实现;
主要是修改ProcessorProvidersBehaviour的getData方法
//VisibleForTesting
<T> Observable<T> getData(final ConfigProvider configProvider) {
return (Observable<T>) Observable.just(
twoLayersCache.retrieve(configProvider.getProviderKey(), configProvider.getDynamicKey(),
configProvider.getDynamicKeyGroup(), useExpiredDataIfLoaderNotAvailable,
configProvider.getLifeTimeMillis(), configProvider.isEncrypted()))
.map(new Func1<Record, Observable<Reply>>() {
@Override public Observable<Reply> call(final Record record) {
//evict() true no cache ,false cache data
if (record != null && !configProvider.evictProvider().evict()) {
//从网络获取数据
return getDataFromClond(configProvider, record);
}
//从网络获取数据如果失败,使用缓存数据
return getDataFromLoader(configProvider, record);
}
}).flatMap(new Func1<Observable<Reply>, Observable<Object>>() {
@Override
public Observable<Object> call(Observable<Reply> responseObservable) {
return responseObservable.map(new Func1<Reply, Object>() {
@Override
public Object call(Reply reply) {
return getReturnType(configProvider, reply);
}
});
}
});
}
private Observable<Reply> getDataFromLoader(final ConfigProvider configProvider,
final Record record) {
return configProvider.getLoaderObservable().map(new Func1() {
@Override public Reply call(Object data) {
//has Data
boolean useExpiredData = configProvider.useExpiredDataIfNotLoaderAvailable() != null ?
configProvider.useExpiredDataIfNotLoaderAvailable()
: useExpiredDataIfLoaderNotAvailable;
if (data == null && useExpiredData && record != null) {
return new Reply(record.getData(), record.getSource(), configProvider.isEncrypted());
}
clearKeyIfNeeded(configProvider);
if (data == null) {
throw new RxCacheException(Locale.NOT_DATA_RETURN_WHEN_CALLING_OBSERVABLE_LOADER
+ " "
+ configProvider.getProviderKey());
}
//保存缓存数据
twoLayersCache.save(configProvider.getProviderKey(), configProvider.getDynamicKey(),
configProvider.getDynamicKeyGroup(), data, configProvider.getLifeTimeMillis(),
configProvider.isExpirable(), configProvider.isEncrypted());
return new Reply(data, Source.CLOUD, configProvider.isEncrypted());
}
}).onErrorReturn(new Func1() {
@Override public Object call(Object o) {
boolean useExpiredData = configProvider.useExpiredDataIfNotLoaderAvailable() != null ?
configProvider.useExpiredDataIfNotLoaderAvailable()
: useExpiredDataIfLoaderNotAvailable;
if (record != null) {
//请求失败,并且缓存数据存在,使用缓存数据
return new Reply(record.getData(), record.getSource(), configProvider.isEncrypted());
}
throw new RxCacheException(Locale.NOT_DATA_RETURN_WHEN_CALLING_OBSERVABLE_LOADER
+ " "
+ configProvider.getProviderKey(), (Throwable) o);
}
});
}
private Observable<Reply> getDataFromClond(final ConfigProvider configProvider,
final Record record) {
return configProvider.getLoaderObservable().map(new Func1() {
@Override public Reply call(Object data) {
clearKeyIfNeeded(configProvider);
if (data == null) {
throw new RxCacheException(Locale.NOT_DATA_RETURN_WHEN_CALLING_OBSERVABLE_LOADER
+ " "
+ configProvider.getProviderKey());
}
//仅仅使用网络数据
return new Reply(data, Source.CLOUD, configProvider.isEncrypted());
}
}).onErrorReturn(new Func1() {
@Override public Object call(Object o) {
throw new RxCacheException(Locale.NOT_DATA_RETURN_WHEN_CALLING_OBSERVABLE_LOADER
+ " "
+ configProvider.getProviderKey(), (Throwable) o);
}
});
}
使用方式会变一下
/**
*
* @param update 是否更新,如果设置为true,向服务器请求数据,如果成功使用新数据,失败使用缓存数据
* @return
*/
public Observable<Reply<List<User>>> getUsers(int idLastUserQueried, final boolean update) {
//这里设置idLastUserQueried为DynamicKey,
return cacheProviders.getUsers(restApi.getUsers(idLastUserQueried, USERS_PER_PAGE), new DynamicKey(idLastUserQueried), new EvictDynamicKey(update));
}
例子源码li-MVPArms
给个start