内容简介:okHttp--Retrofit网络缓存设置总结
1.有网的时候所有接口不使用缓存 2.指定的接口产生缓存文件,其他接口不会产生缓存文件 3.无网的时候指定的接口使用缓存数据.其他接口不使用缓存数据
1.网络拦截器(关键)
提示:只能缓存Get请求
Interceptor cacheInterceptor = new Interceptor() { @Override public Response intercept(Chain chain) throws IOException { //拿到请求体 Request request = chain.request(); //读接口上的@Headers里的注解配置 String cacheControl = request.cacheControl().toString(); //判断没有网络并且添加了@Headers注解,才使用网络缓存. if (!Utils.isOpenInternet()&&!TextUtils.isEmpty(cacheControl)){ //重置请求体; request = request.newBuilder() //强制使用缓存 .cacheControl(CacheControl.FORCE_CACHE) .build(); } //如果没有添加注解,则不缓存 if (TextUtils.isEmpty(cacheControl) || "no-store" .contains(cacheControl)) { //响应头设置成无缓存 cacheControl = "no-store"; } else if (Utils.isOpenInternet()) { //如果有网络,则将缓存的过期时间,设置为0,获取最新数据 cacheControl = "public, max-age=" + 0; }else { //...如果无网络,则根据@headers注解的设置进行缓存. } Response response = chain.proceed(request); HLog.i("httpInterceptor", cacheControl); return response.newBuilder() .header("Cache-Control", cacheControl) .removeHeader("Pragma") .build(); };
具体接口中的使用,添加headers:
/** * 只能缓存get请求. * 这里我设置了1天的缓存时间 * 接口随便写的.哈哈,除了 @Headers(...),其它代码没啥参考价值. */ @Headers("Cache-Control: public, max-age=" + 24 * 3600) @GET("url") Observable<?> queryInfo(@Query("userName") String userName);
关于Cache-Control头的参数说明:
public 所有内容都将被缓存(客户端和代理服务器都可缓存) private 内容只缓存到私有缓存中(仅客户端可以缓存,代理服务器不可缓存) no-cache no-cache是会被缓存的,只不过每次在向客户端(浏览器)提供响应数据时,缓存都要向服务器评估缓存响应的有效性。 no-store 所有内容都不会被缓存到缓存或 Internet 临时文件中 max-age=xxx (xxx is numeric) 缓存的内容将在 xxx 秒后失效, 这个选项只在HTTP 1.1可用, 并如果和Last-Modified一起使用时, 优先级较高 max-stale和max-age一样,只能设置在请求头里面。 同时设置max-stale和max-age,缓存失效的时间按最长的算。(这个其实不用纠结)
还有2个参数:
CacheControl.FORCE_CACHE
强制使用缓存,如果没有缓存数据,则抛出504(only-if-cached) CacheControl.FORCE_NETWORK
强制使用网络,不使用任何缓存.
这两个设置,不会判断是否有网.需要自己写判断. 设置错误会导致,数据不刷新,或者有网情况下,请求不到数据 这两个很关键..可以根据自己的需求,进行切换.
2.设置OkHttpClient
OkHttpClient client = new OkHttpClient.Builder() //添加log拦截器,打印log信息,代码后面贴出 .addInterceptor(loggingInterceptor) //添加上面代码的拦截器,设置缓存 .addNetworkInterceptor(cacheInterceptor) //这个也要添加,否则无网的时候,缓存设置不会生效 .addInterceptor(cacheInterceptor) //设置缓存目录,以及最大缓存的大小,这里是设置10M .cache(new Cache(MyApplication.getContext().getCacheDir(), 10240 * 1024)) .build();
3.完整的代码:
public class RetrofitUtil { /** * 服务器地址 */ private static final String API_HOST = Constant.URLS.BASEURL; private RetrofitUtil() { } public static Retrofit getRetrofit() { return Instanace.retrofit; } private static Retrofit getInstanace() { HttpLoggingInterceptor loggingInterceptor = new HttpLoggingInterceptor(new HttpLoggingInterceptor.Logger() { @Override public void log(String message) { HLog.i("RxJava", message); } }); Interceptor cacheInterceptor = new Interceptor() { @Override public Response intercept(Chain chain) throws IOException { Request request = chain.request(); //有网的时候,读接口上的@Headers里的注解配置 String cacheControl = request.cacheControl().toString(); //没有网络并且添加了注解,才使用缓存. if (!Utils.isOpenInternet()&&!TextUtils.isEmpty(cacheControl)){ //重置请求体; request = request.newBuilder() .cacheControl(CacheControl.FORCE_CACHE) .build(); } //如果没有添加注解,则不缓存 if (TextUtils.isEmpty(cacheControl) || "no-store" .contains(cacheControl)) { //响应头设置成无缓存 cacheControl = "no-store"; } else if (Utils.isOpenInternet()) { //如果有网络,则将缓存的过期事件,设置为0,获取最新数据 cacheControl = "public, max-age=" + 0; }else { //...如果无网络,则根据@headers注解的设置进行缓存. } Response response = chain.proceed(request); HLog.i("httpInterceptor", cacheControl); return response.newBuilder() .header("Cache-Control", cacheControl) .removeHeader("Pragma") .build(); } }; OkHttpClient client = new OkHttpClient.Builder() .addInterceptor(loggingInterceptor) .addNetworkInterceptor(cacheInterceptor) .addInterceptor(cacheInterceptor) .cache(new Cache(MyApplication.getContext().getCacheDir(), 10240 * 1024)) .build(); return new Retrofit.Builder() .client(client) .baseUrl(API_HOST) .addConverterFactory(FastjsonConverterFactory.create()) .addCallAdapterFactory(RxJavaCallAdapterFactory.create()) .build(); } private static class Instanace { private static final Retrofit retrofit = getInstanace(); } }
附上HttpLoggingInterceptor
/** * Created by Sunflower on 2016/1/12. */ public class HttpLoggingInterceptor implements Interceptor { private static final Charset UTF8 = Charset.forName("UTF-8"); public enum Level { /** * No logs. */ NONE, /** * Logs request and response lines. * <p/> * Example: * <pre>{@code * --> POST /greeting HTTP/1.1 (3-byte body) * <p/> * <-- HTTP/1.1 200 OK (22ms, 6-byte body) * }</pre> */ BASIC, /** * Logs request and response lines and their respective headers. * <p/> * Example: * <pre>{@code * --> POST /greeting HTTP/1.1 * Host: example.com * Content-Type: plain/text * Content-Length: 3 * --> END POST * <p/> * <-- HTTP/1.1 200 OK (22ms) * Content-Type: plain/text * Content-Length: 6 * <-- END HTTP * }</pre> */ HEADERS, /** * Logs request and response lines and their respective headers and bodies (if present). * <p/> * Example: * <pre>{@code * --> POST /greeting HTTP/1.1 * Host: example.com * Content-Type: plain/text * Content-Length: 3 * <p/> * Hi? * --> END GET * <p/> * <-- HTTP/1.1 200 OK (22ms) * Content-Type: plain/text * Content-Length: 6 * <p/> * Hello! * <-- END HTTP * }</pre> */ BODY } public interface Logger { void log(String message); /** * A {@link Logger} defaults output appropriate for the current platform. */ Logger DEFAULT = new Logger() { @Override public void log(String message) { Platform.get().log(Platform.WARN,message,null); } }; } public HttpLoggingInterceptor() { this(Logger.DEFAULT); } public HttpLoggingInterceptor(Logger logger) { this.logger = logger; } private final Logger logger; private volatile Level level = Level.BODY; /** * Change the level at which this interceptor logs. */ public HttpLoggingInterceptor setLevel(Level level) { if (level == null) throw new NullPointerException("level == null. Use Level.NONE instead."); this.level = level; return this; } @Override public Response intercept(Chain chain) throws IOException { Level level = this.level; Request request = chain.request(); if (level == Level.NONE) { return chain.proceed(request); } boolean logBody = level == Level.BODY; boolean logHeaders = logBody || level == Level.HEADERS; RequestBody requestBody = request.body(); boolean hasRequestBody = requestBody != null; String requestStartMessage = request.method() + ' ' + request.url(); if (!logHeaders && hasRequestBody) { requestStartMessage += " (" + requestBody.contentLength() + "-byte body)"; } logger.log(requestStartMessage); if (logHeaders) { if (!logBody || !hasRequestBody) { logger.log("--> END " + request.method()); } else if (bodyEncoded(request.headers())) { logger.log("--> END " + request.method() + " (encoded body omitted)"); } else if (request.body() instanceof MultipartBody) { //如果是MultipartBody,会log出一大推乱码的东东 } else { Buffer buffer = new Buffer(); requestBody.writeTo(buffer); Charset charset = UTF8; MediaType contentType = requestBody.contentType(); if (contentType != null) { contentType.charset(UTF8); } logger.log(buffer.readString(charset)); // logger.log(request.method() + " (" + requestBody.contentLength() + "-byte body)"); } } long startNs = System.nanoTime(); Response response = chain.proceed(request); long tookMs = TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - startNs); logger.log(response.code() + ' ' + response.message() + " (" + tookMs + "ms" + ')'); return response; } private boolean bodyEncoded(Headers headers) { String contentEncoding = headers.get("Content-Encoding"); return contentEncoding != null && !contentEncoding.equalsIgnoreCase("identity"); } private static String protocol(Protocol protocol) { return protocol == Protocol.HTTP_1_0 ? "HTTP/1.0" : "HTTP/1.1"; } }
您的喜欢与回复是我最大的动力-_-
以上所述就是小编给大家介绍的《okHttp--Retrofit网络缓存设置总结》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!
猜你喜欢:- 前端实现设置缓存数据定时失效
- Nginx proxy_pass DNS 缓存设置
- [CentOS7]redis设置开机启动,设置密码
- hadoop地址配置、内存配置、守护进程设置、环境设置
- OpenMediaVault 设置
- scrapy代理的设置
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
用户至上:用户研究方法与实践(原书第2版)
凯茜·巴克斯特 / 王兰、杨雪、苏寅 / 机械工业出版社 / 2017-5-1 / 99
《UI/UE系列丛书 用户至上:用户研究方法与实践(原书第2版)》是用户研究方法指南,谷歌用户体验研究员十几年工作经验结晶,从理论到实战,包含完整的实操案例,是设计以人为中心产品的实用手册。 《UI/UE系列丛书 用户至上:用户研究方法与实践(原书第2版)》包含五个部分共15章。入门篇包括第1~5章:介绍用户体验入门,如何理解目标用户,道德与法律问题,如何搭建研究设施,如何选择用户体验研究方......一起来看看 《用户至上:用户研究方法与实践(原书第2版)》 这本书的介绍吧!