RxCacheを変更してRetrofitにキャッシュを先にロードした後にネットワーク機能を要求する
RxJavaファミリーバケツのキャッシュフレームRxCacheはキャッシュ時間の設定のみで、先にキャッシュを入れてからネットワークを要求する機能はできません.RxCacheの基本的な使用は、
http://blog.csdn.net/windboy2014/article/details/52711188
1.ソースコードをよく見てから、ソースコードをキャッシュ機能に変更することができます.RxCacheの構築方法は、Retrofitと同様にBuilderを使用して構築されています.
USingが呼び出され、usingで使用される動的エージェントのすべてのメソッドがInvocationHandlerのinvokeメソッドを実行します.
対応するProxyProvidersのエージェント提供クラスはRxCache 1.5.2バージョンで使用されるdagger 2方式で作成され、ProxyProvidersはInvocationHandlerを実現し、すべての方法はinvoke方法を実行します.
まずProxyTranslatorのprocessMethodメソッドを見てみましょう
メソッドと対応するパラメータを入力し、ConfigProviderを使用してパッケージ化し、パッケージクラスConfigProviderを返します.また、ProcessorProvidersのprocessメソッドを振り返ると、点開はインタフェースであり、対応する実装クラスはdagger 2によって生成されます.RxCacheModule(RxCacheの注記注入パラメータを管理するクラス)のprovideProcessorProvidersメソッドの表示
対応する実装クラスは、P r o s e s o r P o v idersBehaviourのプロセスメソッドです.
Recordはキャッシュデータを記録していますが、キャッシュロジックは基本的にこのクラスのTwoLayersCacheのretrieveメソッドにあります.
RetrieveRecordを呼び出すretrieveRecordメソッド
ソース解読はこの解読に基づいてソースコードを修正し、キャッシュを先に読んでからネットワークを要求する機能を実現する.主にProcessorProvidersBehaviourのgetDataメソッド を修正する.
使い方が変わる
例のソースコードli-MVPArmsはstartをあげます
http://blog.csdn.net/windboy2014/article/details/52711188
1.ソースコードをよく見てから、ソースコードをキャッシュ機能に変更することができます.RxCacheの構築方法は、Retrofitと同様にBuilderを使用して構築されています.
providers = new RxCache.Builder()
.persistence(cacheDir, new GsonSpeaker())
.using(Providers.class);
USingが呼び出され、usingで使用される動的エージェントのすべてのメソッドがInvocationHandlerのinvokeメソッドを実行します.
public 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バージョンで使用されるdagger 2方式で作成され、ProxyProvidersはInvocationHandlerを実現し、すべての方法はinvoke方法を実行します.
@Override public Object invoke(final Object proxy, final Method method, final Object[] args)
throws Throwable {
return Observable.defer(new Func0>() {
@Override public Observable
まず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メソッドを振り返ると、点開はインタフェースであり、対応する実装クラスはdagger 2によって生成されます.RxCacheModule(RxCacheの注記注入パラメータを管理するクラス)のprovideProcessorProvidersメソッドの表示
@Provides ProcessorProviders provideProcessorProviders(
ProcessorProvidersBehaviour processorProvidersBehaviour) {
return processorProvidersBehaviour;
}
対応する実装クラスは、P r o s e s o r P o v idersBehaviourのプロセスメソッドです.
@Override
public Observable process(final ConfigProvider configProvider) {
return (Observable) Observable.defer(new Func0>() {
@Override public Observable
Recordはキャッシュデータを記録していますが、キャッシュロジックは基本的にこのクラスのTwoLayersCacheのretrieveメソッドにあります.
public Record retrieve(String providerKey, String dynamicKey, String dynamicKeyGroup,
boolean useExpiredDataIfLoaderNotAvailable, Long lifeTime, boolean isEncrypted) {
return retrieveRecord.retrieveRecord(providerKey, dynamicKey, dynamicKeyGroup,
useExpiredDataIfLoaderNotAvailable, lifeTime, isEncrypted);
}
RetrieveRecordを呼び出すretrieveRecordメソッド
Record retrieveRecord(String providerKey, String dynamicKey, String dynamicKeyGroup,
boolean useExpiredDataIfLoaderNotAvailable, Long lifeTime, boolean isEncrypted) {
String composedKey = composeKey(providerKey, dynamicKey, dynamicKeyGroup);
//
Record 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;
}
ソース解読はこの解読に基づいて
//VisibleForTesting
Observable getData(final ConfigProvider configProvider) {
return (Observable) Observable.just(
twoLayersCache.retrieve(configProvider.getProviderKey(), configProvider.getDynamicKey(),
configProvider.getDynamicKeyGroup(), useExpiredDataIfLoaderNotAvailable,
configProvider.getLifeTimeMillis(), configProvider.isEncrypted()))
.map(new Func1>() {
@Override public Observable 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>() {
@Override
public Observable call(Observable responseObservable) {
return responseObservable.map(new Func1() {
@Override
public Object call(Reply reply) {
return getReturnType(configProvider, reply);
}
});
}
});
}
private Observable 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 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>> 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をあげます