修改RxCache为Retrofit增加先加载缓存后请求网络功能

RxJava全家桶中的缓存框架RxCache只有缓存时间的设置,并不能做到先加缓存后请求网络的功能,RxCache的基本使用,请看

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版本中使用的dagger2方式创建,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 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  Observable process(final ConfigProvider configProvider) {
    return (Observable) Observable.defer(new Func0>() {
      @Override public Observable call() {
        if (hasProcessesEnded) {
          return getData(configProvider);
        }

        return oProcesses.flatMap(new Func1>() {
          @Override public Observable call(Void aVoid) {
            return getData(configProvider);
          }
        });
      }
    });
  }

  //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) {
            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>() {
          @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) {
        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  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;
  }

源码解读依据这个解读的

  1. 修改源码,达到先读缓存后请求网络的功能实现;
    主要是修改ProcessorProvidersBehaviour的getData方法

  //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

你可能感兴趣的:(Rxjava,网络请求,retrofit)