美文网首页Android TechAndroid知识编程
MVP架构实现的Github客户端(4-加入网络缓存)

MVP架构实现的Github客户端(4-加入网络缓存)

作者: anly_jun | 来源:发表于2016-08-15 00:24 被阅读4401次

    系列文章:
    1-准备工作
    2-搭建项目框架
    3-功能实现
    4-加入网络缓存

    经过前面的几项工作, 项目框架和功能开发规范已经差不过出来了. 接下来要做的就说迭代功能, 和完善细节了.

    今天我们要做的是给我们的网络请求加入缓存机制. 类似于一般的阅读类App, 缓存机制一般如下:

    1. 有网时根据设置的Cache Control时间来判断是使用缓存还是重新做网络请求.
    2. 无网络环境下直接使用缓存, 保证阅读体验.

    1, 为什么要加缓存

    缓存之所以必要, 最重要的是能给用户以良好的体验.
    另外网络数据缓存也是App网络流量优化, 电量优化的一个必要手段.

    2, 好了, 废话还是少说, 直接开始

    要做到缓存仅需要三步:

    1. 请求客户端配置缓存目录.
    2. Request中须带有Cache-Control的header, 以便请求时决定是否使用缓存.
    3. Response中须带有Cache-Control的header, 以告知Client端该响应是否可以缓存, 以及缓存时效.

    2.1 配置OkHttp的缓存目录

    • 设置Cache Dir
    private static final long CACHE_SIZE = 1024 * 1024 * 50;
    
    @Override
    public OkHttpClient.Builder customize(OkHttpClient.Builder builder) {
       // set cache dir
       File cacheFile = new File(mContext.getCacheDir(), "github_repo");
       Cache cache = new Cache(cacheFile, CACHE_SIZE);
       builder.cache(cache);
    
       ...
       
       return builder;
    }
    

    2.2 配置Retrofit Request接口的"Cache-Control" Header

    顾名思义, "Cache-Control"请求头就是用来控制缓存的. 它有一些属性值来指定缓存的属性, 诸如公共属性, 是否可缓存以及缓存的有效期等.

    关于"Cache-Control"的详细解释和使用请自行google...在此略过.
    个人也有计划写一些关于HTTP协议相关的基础知识, 会聊到Cache-Control, 敬请期待.

    以获取Github Trending这个接口为例:

    @Headers("Cache-Control: public, max-age=180")
    @GET("trending?languages[]=java&languages[]=swift&languages[]=objective-c&languages[]=bash&languages[]=python&languages[]=html")
    Observable<TrendingResultResp> getTrendingRepos();
    
    • public 指示响应可被任何缓存区缓存
    • max-age=180 指示该请求的缓存的有效期为3分钟(以秒为单位).

    2.3 配置Response中的"Cache-Control" Header

    众所周知, Response是由服务器控制的, 我们如何加入"Cache-Control"头呢? 方法有二:

    1. 说服服务器的开发人员按照你的需求在response中加入Cache-Control.
    2. 使用我们接下来要说的OkHttp的拦截器interceptor.

    大多数情况下, 服务器可能并不受我们控制. 服务器开发人员开发多个系统, 对端的缓存需求不熟悉, 又或是服务器接口并不是我们自己开发的, 例如本系列做的这个GithubApp.

    所幸, OkHttp提供了interceptor来让我们对request, response进行拦截处理, 加入我们想要的请求头等.

    如下是本例使用的Cache Interceptor:

    private final Interceptor mCacheControlInterceptor = new Interceptor() {
       @Override
       public Response intercept(Chain chain) throws IOException {
           Request request = chain.request();
           if (!NetworkUtil.isNetworkAvailable(mContext)) {
               request = request.newBuilder()
                       .cacheControl(CacheControl.FORCE_CACHE)
                       .build();
           }
    
           Response originalResponse = chain.proceed(request);
    
           if (NetworkUtil.isNetworkAvailable(mContext)) {
    
               String cacheControl = request.cacheControl().toString();
    
               return originalResponse.newBuilder()
                       .header("Cache-Control", cacheControl)
                       .build();
           } else {
               return originalResponse.newBuilder()
                       .header("Cache-Control", CacheControl.FORCE_CACHE.toString())
                       .build();
           }
       }
    };
    

    如下拦截器, 做了:

    1. 对于request, 当没有网络时, 使用CacheControl.FORCE_CACHE, 即使用缓存. (正常情况使用2.2配置的Cache-Control)
    2. 对于response, 有网时, 加入和request一样的Cache-Control;
    3. 对于response, 无网, 使用CacheControl.FORCE_CACHE(这种情况较为少见).

    做好了拦截器, 不要忘记加到OkHttpClient中:

    builder.addNetworkInterceptor(mCacheControlInterceptor);
    

    3, 严重提醒

    严重注意, 在加入interceptor时:
    使用的是addNetworkInterceptor, 而非addInterceptor.

    二者区别参见OkHttp wiki的Interceptor介绍, 在此就借个图来用下:

    okhttp interceptor

    正所谓一图千字, 可以很清楚的看到CACHE的层次了...具体的分析大家还是Read the fucking source code吧:)

    这里就说明下为什么要使用addNetworkInterceptor吧.

    某些情况下, 服务器返回的response是会带有Cache-Control的, 如果这个Cache-Control的时效配置和你想要的不一致, 或是更甚者服务器传回类似这样的:

    no cache

    那么我们就悲剧了, no-cache, 意味着响应不会被缓存.

    • 当然, 如果服务器没有定制response的Cache-Control属性的话, 我们使用addInterceptor来添加拦截器, 还是可以给reponse加入Cache-Control并使其缓存的.

    • 关于Interceptor和NetworkInterceptor的区别, 建议大家还是读源码...在此略过.

    • 稳妥起见, 完全由客户端可控的话, 还是使用addNetworkInterceptor吧.

    4, 结语

    回顾下, 加入网络缓存的几步:

    1. 配置缓存目录
    2. 配置request Cache-Control
    3. 配置response Cache-Control

    虽说简单, 但是个中的确包含了很多知识点. Cache-Control属性的使用, 意义; OkHttp的拦截器; Retrofit的header配置等等.

    还是那句话, 更多的是希望大家能够在学到东西的同时, 了解更多其相关的原理, 或是学习方法.

    知其然, 知其所以然.

    本文例子, 完整代码

    相关文章

      网友评论

      • 洛埋名:很全很强大。
      • biginsect:请问下登录功能 是需要获取权限的吧Github上面 Developer settings 有三个内容 是要申请Github Apps 和 token么,我也在做一款github app,有点懵
      • 68768b474bfc:请问缓存请求有什么作用,一般都缓存响应吧 :joy:
        anly_jun:@TellH 配置request的cache-control header并非是缓存请求, 而是告知系统该请求的使用缓存模式.
      • cbe7593ec1cc:请教个问题,cache文件夹下缓存有json的文件,但是没网时数据不显示,为啥呢
        lhl_012:以前遇到好像wifi和断网是不同的状态,返回的header
        anly_jun:@天桥下算命少年 看下request的cache control有没有配置, 另外response的cache control时间是否已过期
      • longzekai:github 上缺少了这个类DaggerApplicationComponent? 劳烦楼主看下。
        longzekai: @anly_jun 好的
        anly_jun: @longzekai Dagger2编译自动生成的~请先编译下😊
      • lishiwei:赞赞。

      本文标题:MVP架构实现的Github客户端(4-加入网络缓存)

      本文链接:https://www.haomeiwen.com/subject/sdqusttx.html