okhttp添加本地缓存(支持get post)

来源:互联网 发布:tensorflow函数 编辑:程序博客网 时间:2024/05/29 13:47

要实现一个okhttp的缓存策略,就是对应某些个接口缓存,第一反应就是拦截器,拦截器是okhttp中的精华所在,大体逻辑:

1.拿到文件的最后修改时间和当前时间对比,大于30分钟,缓存失效,重新请求并缓存数据

2.对比时间,小于30分钟,直接从缓存读取,重新构造response在拦截器方法中返回


上代码:

public class CacheInterceptor implements Interceptor {    private List<String> cacheRouters = new ArrayList<String>() {        {            this.add("/upgrade/appupdate");        }    };    private static final long CACHE_TIME = 60*30*1000;    @Override    public Response intercept(Chain chain) throws IOException {        Request request = chain.request();        String path = request.url().url().getPath();        if (!cacheRouters.contains(path))            return chain.proceed(request);        //需要拦截的路由        File file = createCacheFile(path);        long lastModified = file.lastModified();        long nowTime = System.currentTimeMillis();        Response response = null;        if (nowTime - lastModified > CACHE_TIME || file.length() == 0) {            //缓存文件过期(或者第一次创建内容是空的),去请求并且缓存下来            response = reqAndCache(chain.proceed(request), file);        } else {            //缓存文件没过期,读取缓存,构建response对象            response = getCache(request,file);        }        return response;    }

接着是重新请求的方法:

    private Response reqAndCache(Response response,File file){        String body = null;        try {            body = response.body().string();            JSONObject object = new JSONObject(body);            int code = object.optInt("code", 0);            if(code == 200)                write(file,body);        } catch (Exception e) {            e.printStackTrace();        }        return response.newBuilder().body(ResponseBody.create(response.body().contentType(),body)).build();    }
这里的response.newBuilder()是因为  调用了一次response.body().string()之后和服务器的链接流就关闭了,把这个response给用户是无效的

走缓存并构建response的方法:

    private Response getCache(Request request, File file) {        MediaType json = MediaType.parse("text/html; charset=utf-8");        return new Response.Builder().                body(ResponseBody.create(json,readFile(file).getBytes()))                .request(request)                .protocol(Protocol.HTTP_1_1)                .code(200)                .message("OK")                .build();    }
这里之所以重新new一个 response,是因为调用chain.process(request)是需要走网络返回一个socket流,对于没有网络的缓存就不支持了


对于缓存文件的读写我是用的okio的api   okio的读写都有一个环形链表的buffer给于支持,效率非常之高



贴上整个拦截器的代码:


public class CacheInterceptor implements Interceptor {    private List<String> cacheRouters = new ArrayList<String>() {        {            this.add("/upgrade/appupdate");        }    };    private static final long CACHE_TIME = 60*30*1000;    @Override    public Response intercept(Chain chain) throws IOException {        Request request = chain.request();        String path = request.url().url().getPath();        if (!cacheRouters.contains(path))            return chain.proceed(request);        //需要拦截的路由        File file = createCacheFile(path);        long lastModified = file.lastModified();        long nowTime = System.currentTimeMillis();        Response response = null;        if (nowTime - lastModified > CACHE_TIME || file.length() == 0) {            //缓存文件过期(或者第一次创建内容是空的),去请求并且缓存下来            response = reqAndCache(chain.proceed(request), file);        } else {            //缓存文件没过期,读取缓存,构建response对象            response = getCache(request,file);        }        return response;    }    private Response getCache(Request request, File file) {        MediaType json = MediaType.parse("text/html; charset=utf-8");        return new Response.Builder().                body(ResponseBody.create(json,readFile(file).getBytes()))                .request(request)                .protocol(Protocol.HTTP_1_1)                .code(200)                .message("OK")                .build();    }    private Response reqAndCache(Response response,File file){        String body = null;        try {            body = response.body().string();            JSONObject object = new JSONObject(body);            int code = object.optInt("code", 0);            if(code == 200)                write(file,body);        } catch (Exception e) {            e.printStackTrace();        }        return response.newBuilder().body(ResponseBody.create(response.body().contentType(),body)).build();    }    private File createCacheFile(String path) {        File file = new File(getDiskCacheDir("stockcode"), MD5Util.myMd5(path) + ".json");        if (!file.exists())            try {                file.createNewFile();            } catch (IOException e) {                e.printStackTrace();            }        return file;    }    private File getDiskCacheDir(String uniqueName) {        String cachePath = MyApplication.CONTEXT.getExternalCacheDir().getPath();        File file = new File(cachePath + File.separator + uniqueName);        if (!file.exists())            file.mkdirs();        Logs.e("size",file.length());        return file;    }    public String readFile(File file){        Source source;        BufferedSource bufferedSource = null;        String read = "";        try {            source = Okio.source(file);            bufferedSource = Okio.buffer(source);            read = bufferedSource.readUtf8();        } catch (IOException e) {            e.printStackTrace();        } finally {            try {                if (null != bufferedSource) {                    bufferedSource.close();                }            } catch (IOException e) {                e.printStackTrace();            }        }        return read;    }    private void write(File file,String content){        Sink sink;        BufferedSink bufferedSink = null;        try {            sink = Okio.sink(file);            bufferedSink = Okio.buffer(sink);            bufferedSink.writeUtf8(content);            bufferedSink.flush();        } catch (IOException e) {            e.printStackTrace();        } finally {            try {                if (null != bufferedSink) {                    bufferedSink.close();                }            } catch (IOException e) {                e.printStackTrace();            }        }    }}