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

7 篇文章 0 订阅
5 篇文章 0 订阅
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> 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;
  }

源码解读依据这个解读的

  1. 修改源码,达到先读缓存后请求网络的功能实现;
    主要是修改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

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 5
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值