okHttp--Retrofit网络缓存设置总结

栏目: Java · 发布时间: 7年前

内容简介: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-stalemax-age一样,只能设置在请求头里面。

同时设置max-stalemax-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网络缓存设置总结》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

On LISP

On LISP

Paul Graham / Prentice Hall / 09 September, 1993 / $52.00

On Lisp is a comprehensive study of advanced Lisp techniques, with bottom-up programming as the unifying theme. It gives the first complete description of macros and macro applications. The book also ......一起来看看 《On LISP》 这本书的介绍吧!

在线进制转换器
在线进制转换器

各进制数互转换器

随机密码生成器
随机密码生成器

多种字符组合密码

HEX CMYK 转换工具
HEX CMYK 转换工具

HEX CMYK 互转工具