教你如何使用okhttp缓存


本文更新于2017-10-15,基于com.squareup.okhttp3:okhttp:3.9.0测试,最好查看原文,因为可能会更新

转载务必注明出处http://blog.csdn.net/u014614038/article/details/51210685


使用方法很简单:


1.首先进行先进行设置:

private static final OkHttpClient client;
    private static final long cacheSize = 1024 * 1024 * 20;// 缓存文件最大限制大小20M
    private static String cacheDirectory = Environment.getExternalStorageDirectory() + "/okttpcaches"; // 设置缓存文件路径
    private static Cache cache = new Cache(new File(cacheDirectory), cacheSize);  //

    static {
        //如果无法生存缓存文件目录,检测权限使用已经加上,检测手机是否把文件读写权限禁止了
        OkHttpClient.Builder builder = new OkHttpClient.Builder();
        builder.connectTimeout(8, TimeUnit.SECONDS); // 设置连接超时时间
        builder.writeTimeout(8, TimeUnit.SECONDS);// 设置写入超时时间
        builder.readTimeout(8, TimeUnit.SECONDS);// 设置读取数据超时时间
        builder.retryOnConnectionFailure(true);// 设置进行连接失败重试
        builder.cache(cache);// 设置缓存
        client = builder.build();

    }




注意的是:okhttp只会对get请求进行缓存,post请求是不会进行缓存,这也是有道理的,因为get请求的数据一般是比较持久的,而post一般是交互操作,没太大意义进行缓存。


2.进行get请求:

一般来说的是,我们get请求有时有不一样的需求,有时需要进行缓存,有时需要直接从网络获取,有时只获取缓存数据,这些处理,okhttp都有帮我们做了,我们做的只需要设置就是了。下面是整理的各种需求的设置与使用方法。


  1.进行get请求,将数据缓存返回。(请求失败、无网络也返回缓存数据)

 /** 如果没有缓存,进行get请求获取服务器数据并缓存起来
     * 如果缓存已经存在:不超过maxAge---->不进行请求,直接返回缓存数据
     *                    超出了maxAge--->发起请求获取数据更新,请求失败返回旧的缓存数据
     * @param url
     * @param cache_maxAge_inSeconds
     * @param responseListener
     * @return
     */
    public static Call DoGetAndCache(String url, int cache_maxAge_inSeconds, 
                                     final NetWorkResponseListener responseListener) {
        Request request = new Request.Builder()
                .cacheControl(new CacheControl.Builder().maxAge(cache_maxAge_inSeconds, TimeUnit.SECONDS)
                        .build())
                .url(url).build();

        Call call = client.newCall(request);
        startRequest(call, responseListener);
        return call;
    }


2.进行get请求,将数据缓存返回,并指定缓存数据有效时间。

  /** 如果没有缓存,进行get请求获取服务器数据并缓存起来
     * 如果缓存已经存在:不超过maxStale---->不进行请求,直接返回缓存数据
     *                    超出了maxStale--->发起请求获取数据更新,请求失败返回失败
     * @param url
     * @param cache_maxStale_inSeconds
     * @param responseListener
     * @return
     */
    public static Call DoGetAndCacheInStaleTime(String url, int cache_maxStale_inSeconds,
                                     final NetWorkResponseListener responseListener) {
        Request request = new Request.Builder()
                .cacheControl(new CacheControl.Builder().maxStale(cache_maxStale_inSeconds, TimeUnit.SECONDS)
                        .build())
                .url(url).build();

        Call call = client.newCall(request);
        startRequest(call, responseListener);
        return call;
    }

maxAge与maxStale的区别:

maxAge:没有超出maxAge,不管怎么样都是返回缓存数据,超过了maxAge,发起新的请求获取数据更新,请求失败返回缓存数据。

maxStale:没有超过maxStale,不管怎么样都返回缓存数据,超过了maxStale,发起请求获取更新数据,请求失败返回失败


  3.进行get请求,只使用网络数据

/**
     * get请求,只获取网络数据
     *
     * @param url
     * @param responseListener
     * @return
     */
    public static Call DoGetOnlyNet(String url, final NetWorkResponseListener responseListener) {
        Request request = new Request.Builder().cacheControl( CacheControl.FORCE_NETWORK).url(url)
                .build();
        Call call = client.newCall(request);
        startRequest(call, responseListener);
        return call;
    }


  4.get请求,只使用缓存数据

  /**
     * get请求, 只使用缓存,注意,如果没有缓存数据,返回504,否则就返回缓存数据,不管缓存数据是否超出max-age与max-stale
     *
     * @param url
     * @param responseListener
     */
    public static Call DoGetOnlyCache(String url, final NetWorkResponseListener responseListener) {
        Request request = new Request.Builder().cacheControl( CacheControl.FORCE_CACHE).url(url)
                .build();
        Call call = client.newCall(request);
        startRequest(call, responseListener);
        return call;
    }


startrequest(Call call0):

private static void startRequest(final Call call0,
                                     final NetWorkResponseListener responseListener) {
        try {
            call0.enqueue(new Callback() {
                @Override
                public void onFailure(Call arg0, IOException arg1) {
                    String message = "未知错误";
                    if (arg1 != null) {
                        Throwable t = arg1.getCause();
                        message = arg1.toString();
                        if (t != null) {
                            if (t instanceof SocketTimeoutException) {
                                message = "请求超时了";
                            } else if (t instanceof UnknownHostException) {
                                message = "UnknownHostException,无法访问该地址";
                            }

                        }
                    }

                    responseListener.onFail(message);

                }

                @Override
                public void onResponse(Call arg0, Response response) throws IOException {

                    if (response.isSuccessful()) {
                        responseListener.onSuccess(response.body().string() + "");
                    } else {
                        if(response.cacheResponse()!=null){
                            responseListener.onSuccess(response.cacheResponse().body().string() + "");
                        }else {
                            responseListener.onFail("response失败了,连接状态码为:" + response.code());
                        }
                    }


                }

            });

        } catch (Exception e) {
            responseListener.onFail("请求异常:" + e.toString());

        }
    }

下面测试一下,设置缓存maxStale为10秒,我们将请求返回的数据打印出来:



     上面图片的1是点击获取的服务器的数据,获取后断开网络然后继续点击,可以看到2还能获取到数据,说明这是缓存的数据,当到3时,差不多就是十秒的时间,可以看到,获取数据失败了,这时已经去服务器获取数据了,由于断开网络所以请求失败。


可能出现的问题:


1.缓存文件没有生成。

只要配置成功,缓存目录一定会有的,所以看看:1.权限配置是否完整  2.手机应用权限是不是拒绝了。

    <uses-permission android:name="android.permission.INTERNET"/>
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>

2.缓存没有生成,maxAge等配置了不起作用。

可能是请求的服务器不支持配置返回maxAge等头数据,建议通过配置缓存拦截器去添加这些参数:

static {  
        //如果无法生存缓存文件目录,检测权限使用已经加上,检测手机是否把文件读写权限禁止了  
        OkHttpClient.Builder builder = new OkHttpClient.Builder();  
        builder.connectTimeout(8, TimeUnit.SECONDS); // 设置连接超时时间  
        builder.writeTimeout(8, TimeUnit.SECONDS);// 设置写入超时时间  
        builder.readTimeout(8, TimeUnit.SECONDS);// 设置读取数据超时时间  
        builder.retryOnConnectionFailure(true);// 设置进行连接失败重试  
        builder.cache(cache);// 设置缓存  
        builder.addNetworkInterceptor(new CacheInterceptor());//缓存拦截器,通过这个设置maxAge与maxStale 
        client = builder.build();  
  
    }  
  
    /** 
     * 缓存拦截器 
     */  
    private static class CacheInterceptor implements Interceptor {  
  
        @Override  
        public Response intercept(Chain chain) throws IOException {  
  
            Response originResponse = chain.proceed(chain.request());  
  
            //设置缓存时间为,并移除了pragma消息头,移除它的原因是因为pragma也是控制缓存的一个消息头属性  
            return originResponse.newBuilder().removeHeader("pragma")  
                    .header("Cache-Control", "max-age=10")//设置10秒  
                    .header("Cache-Control", "max-stale=30").build();  
        }  
    }  


3.缓存返回总是返回504或者无法返回缓存数据,可是缓存文件又已经生成

如果get请求是带参数的话,可能参数值不同导致拼接的url地址不一样,会被认为是新地址去重新发起请求获取数据,当然被认为没有缓存数据


以上都是本人查看官方文档并进行测试验证后整理的,有不对的地方,万请指正。

封装了比较完整的网络请求工具类,包括请求相关信息的判断以及请求日志记录等,需要的可以看看:

点击进入






©️2020 CSDN 皮肤主题: 创作都市 设计师:CSDN官方博客 返回首页