OkHttp缓存功能的应用

1.首先要设置okhttp启用缓存功能 设置缓存目录和缓存大小

client.setCache(new Cache(context.getCacheDir(),maxCacheSize));

2.当然,设置了缓存和目录还是不够的,http请求总该有个过期时间吧,缓存是由HTTP消息头中的”Cache-control”来控制的,常见的取值有private、no-cache、max-age、must-revalidate等,默认为private。
下面是作用:

public 所有内容都将被缓存

private 内容只缓存到私有缓存中

no-cache 所有内容都不会被缓存

no-store 所有内容都不会被缓存到缓存或 Internet 临时文件中

must-revalidation/proxy-revalidation 如果缓存的内容失效,请求必须发送到服务器/代理以进行重新验证

max-age=xxx (xxx is numeric) 缓存的内容将在 xxx 秒后失效, 这个选项只在HTTP 1.1可用, 并如果和Last-Modified一起使用时, 优先级较高

一般来说我们用到的是no-cache和max-age比较多,既然我们要实现缓存,那么自然就要在我们的每一条的请求头里面添加这个属性,OkHttp提供了Interceptor 拦截器这个东西,做过web应该明白,就是在你一条http请求要发送之前,拦截下来,做一些处理然后再继续发送,因此,我们就可以添加一个拦截器,在请求前把Cache-control:max-age=36000添加到请求头里去。

Interceptor cacheInterceptor = new Interceptor() {
    @Override public Response intercept(Chain chain) throws IOException {
        Response originalResponse = chain.proceed(chain.request());
                        return originalResponse.newBuilder()
                .removeHeader("Pragma")//Pragma:no-cache。在HTTP/1.1协议中,它的含义和Cache-Control:no-cache相同。为了确保缓存生效
                .header("Cache-Control", String.format("max-age=%d", maxCacheAge))//添加缓存请求头
                .build();
    }
};

3.嗯,差不多到这一步就已经快完成了,剩下的就是调用OkHttp的方法了。

Request.Builder requestBuilder = new Request.Builder().url(url).cacheControl(cacheControl);

一个OkHttp的请求大致是这样子的,url是必须的,然后如果我们要实现缓存,cacheControl也是必须的,OkHttp提供了CacheControl这个类,里面FORCE_CACHE 和FORCE_NETWORK分别表示只从缓存获取数据和只通过网络请求获取数据,有了前面的两步设置,这时我们是可以通过设置FORCE_CACHE 来从缓存获取数据而不通过网络获取服务器的数据的(前提是你本地要有缓存,也就是必须先通过网络请求获取到一次数据才能获取到缓存),代码没什么,就不贴了。

嗯,我们的网络请求实现本地缓存已经实现,当你网络请求失败的时候又不希望展示给用户的是一片空白,那你就可以调用本地之前的缓存了!!你别告诉我这样你就满足了,这每次都要判断是不是请求失败了,要不要请求缓存,这想想都蛋疼啊!!!

所以我对OkHttp进行封装,实现了只查询缓存,网络请求失败自动查询本地缓存等功能
支持4种不同的查询方式

*ONLY_NETWORK 只查询网络数据

*ONLY_CACHED 只查询本地缓存

*CACHED_ELSE_NETWORK 先查询本地缓存,如果本地没有,再查询网络数据

*NETWORK_ELSE_CACHED 先查询网络数据,如果没有,再查询本地缓存

支持get和post请求,默认查询方式为NETWORK_ELSE_CACHED,可通过Builder来指定默认查询方式

先贴代码

//实现一个最基本的请求方法
private Call request(Request request, Callback callback){
    if(DEBUG){
        Log.d("OKHttp",request.toString());
    }
    Call call = client.newCall(request);
    call.enqueue(callback);
    return call;
}
//实现自己的回调,添加了onStart和onFinish方法
public abstract class Callback implements com.squareup.okhttp.Callback {
    public void onStart(){

    }    
    public void onFinish(){

    }
    public abstract void onFailure(Request request, IOException e);
    public abstract void onResponse(Response response) throws IOException;
}
//定义一个公用的方法,实现最基本的封装,无论是post还是get都适用
private void request(String url, String method, RequestBody requestBody, final CacheControl cacheControl, Headers headers,Object tag ,final Callback callback){
    final Request.Builder requestBuilder = new Request.Builder().url(url).cacheControl(cacheControl);
    if(headers!=null){
        requestBuilder.headers(headers);
    }
    requestBuilder.method(method,requestBody);//如果是get请求,这里requestBody就应该传个null
    requestBuilder.tag(tag==null?url:tag);//OkHttp的tag是对请求的标志,可以通过tag来获取到请求和取消请求,这里如果你不传,就将当前url设置为tag 
    final Request request = requestBuilder.build();
    request(request,new Callback() {
        //这里是回调
        @Override
        public void onStart() {
            if(callback!=null){
                    callback.onStart();
                }
        }  
        @Override            
        public void onFinish() {                
        if(callback!=null){
                callback.onFinish();
            }
        }            
        @Override            
        public void onFailure(Request request, IOException e) {                
        if(callback!=null){
                callback.onFailure(request,e);
                callback.onFinish();
            }
        }            
        @Override            
        public void onResponse(Response response) throws IOException {                
            if(response.code()==504){
                //OkHttp如果缓存请求不到是会报504的                    
                if(CacheControl.FORCE_CACHE == cacheControl){                        
                    if(callback!=null){
                        callback.onFailure(request,new IOException("cached not found"));
                        callback.onFinish();
                    }                        
                    return;
                }
            }                
            if(callback!=null){
                callback.onResponse(response);
                callback.onFinish();
            }
        }
    });
}
//实现只请求网络和只请求缓存的方法 
public void requestFromNetwork(final String url,String method,RequestBody requestBody, Headers headers,Object tag,final Callback callback){
        request(url,method,requestBody,CacheControl.FORCE_NETWORK,headers,tag,callback);
}    
public void requestFromCached(String url,String method,RequestBody requestBody,Headers headers ,Object tag,final Callback callback){

   request(url,method,requestBody,CacheControl.FORCE_CACHE,headers,tag,callback);
}

定义了4种请求类型
*ONLY_NETWORK 只查询网络数据

*ONLY_CACHED 只查询本地缓存

*CACHED_ELSE_NETWORK 先查询本地缓存,如果本地没有,再查询网络数据

*NETWORK_ELSE_CACHED 先查询网络数据,如果没有,再查询本地缓存

前两种都没什么好说的,直接调用写好的两个方法requestFromNetwork和requestFromCached就行了
后面两种:
1.CACHED_ELSE_NETWORK 先查询本地缓存,如果本地没有,再查询网络数据,我们就需要自己再传一个Callback c2回调了,当回调执行成功的时候,我们直接就调用方法的回调的onResponse就行,其余情况我们就需要查询网络的数据,到了这一步,说明本地没有缓存了,所以直接调用requestFromNetwork就行

public void request(final String url,final CacheType cacheType,final String method,final RequestBody requestBody,final Headers headers,final Object tag,final Callback callback){
    if(callback!=null)
    callback.onStart();
    switch(cacheType){
        case ONLY_NETWORK://只查询网络数据
            requestFromNetwork(url,method,requestBody,headers,tag,callback);
            break;
        case ONLY_CACHED://只查询本地缓存
            requestFromCached(url,method,requestBody,headers,tag,callback);
            break;
        case CACHED_ELSE_NETWORK:
            requestFromCached(url,method,requestBody,headers,tag,new Callback(){
                @Override 
                public void onStart(){
                    if(callback!=null){
                        callback.onStart();
                    }
                }
                @Override public void onFinish(){
                    if(callback!=null){
                        callback.onFinish();
                    }
                }
                @Override 
                public void onFailure(Request request,IOException e){
                    requestFromNetwork(url,method,requestBody,headers,tag,callback);
                }
                @Override public void onResponse(Response response)throws IOException{
                    if(response.code()==200){
                        //response.isSuccessful()OkHttp是有这个方法判断请求是否成功的,但判断的方法是根据状态码是否是20开头(200,201,202,203等,具体区别就不在这里描述了,有兴趣的百度)来判断的,但只有200返回的数据才是我们想要的                            
                        if(callback!=null){
                            callback.onResponse(response);
                            callback.onFinish();
                        }
                    }else{
                        requestFromNetwork(url,method,requestBody,headers,tag,callback);
                    }
                }
             });
             break;
         case NETWORK_ELSE_CACHED:
            requestFromNetwork(url,method,requestBody,headers,tag,new Callback(){
                @Override public void onStart(){
                    if(callback!=null){
                        callback.onStart();
                    }
                }
                @Override public void onFinish(){
                    if(callback!=null){
                    callback.onFinish();
                    }
                 }
                @Override public void onFailure(Request request,IOException e){
                    requestFromCached(url,method,requestBody,headers,tag,callback);
                }
                @Override public void onResponse(Response response)throws IOException{
                    if(response.code()==200){
                        if(callback!=null){
                            callback.onResponse(response);
                            callback.onFinish();
                        }
                    } else{
                            requestFromCached(url,method,requestBody,headers,tag,callback);
                    }
                }
            });
            break;
    }
}
  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值