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";
    }
}

复制代码

您的喜欢与回复是我最大的动力-_-

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: OkHttp、RxJavaRetrofit是个非常常用的组合,用来进行网络请求和处理。 首先,OkHttp是一个开源的HTTP客户端,提供了简洁的接口,用于与服务器进行通信,并且支持HTTP/2协议,拥有连接池、请求重试和缓存等功能。 然后,RxJava是一个基于观察者模式的异步编程库,可以用于处理异步操作,如网络请求文件IO等。它的核心是Observable(被观察者)和Subscriber(订阅者),通过各种操作符可以对数据进行变换和处理。 最后,Retrofit是一个RESTful风格的HTTP请求库,它基于OkHttp,使用了Retrofit的注解和接口定义的方式,可以方便地进行网络请求。它支持动态代理,可以将网络请求接口转化为对应的HTTP请求,支持同步和异步请求,并且可以将响应数据转化为Java对象。 综上所述,我们可以使用OkHttp作为底层网络库,然后结合RxJavaRetrofit进行网络请求和数据处理。使用Retrofit的注解和接口定义方式,可以简化网络请求的代码,并且通过RxJava的操作符可以对请求结果进行变换和处理,使得代码更加清晰和可读性。 在使用过程中,可以先创建一个Retrofit实例,并指定OkHttpClient作为网络客户端,然后定义一个接口,在该接口中使用Retrofit的注解,定义网络请求的方法。最后,通过创建该接口的实例,即可进行网络请求,并结合RxJava进行操作。 总之,使用OkHttp、RxJavaRetrofit组合进行网络请求可以提高效率和可读性,并且可以处理各种复杂的网络场景,是一种非常实用的方式。 ### 回答2: OKHTTP、RXJavaRetrofit是Android开发中常用的三个库,可以一起使用来进行网络请求和数据处理。 OKHTTP是一个用于处理网络请求的库,可以发送HTTP请求并获取服务器返回的数据。它提供了简洁的API和高效的网络堆栈,可以很好地处理网络请求。我们可以使用OKHTTP来发送SOAP请求到WebService,并获得响应。 RXJava是一个流编程库,它提供了一种被观察者和观察者模式,可以简化异步操作和事件处理。我们可以使用RXJava来处理OKHTTP返回的响应数据,在主线程或后台线程中进行处理,实现数据的异步处理和流式编程。 Retrofit是一个基于OKHTTP的RESTful风格的网络请求库,它提供了一种简洁的方式来定义和发送HTTP请求,并将响应转换为可用的Java对象。我们可以使用Retrofit来定义WebService接口,然后使用注解来指定请求方法、路径和参数,Retrofit会自动帮我们处理请求和响应。 通过OKHTTP的原生支持、RXJava的异步处理和Retrofit网络请求,我们可以很方便地使用OKHTTP、RXJavaRetrofit一起发送WebService请求。首先,我们可以使用Retrofit定义WebService接口,再使用RXJava来处理OKHTTP返回的响应数据,实现简洁高效的网络请求和数据处理。 综上所述,OKHTTP、RXJavaRetrofit是Android开发中常用的网络请求库,它们能够很好地协作,实现对WebService的请求和响应的处理。通过使用它们,我们可以简化网络请求的编写,并实现高效的数据处理。 ### 回答3: OkHttp、RxJavaRetrofit是三个在Android开发中常用的网络请求库,它们在一起能够提供更加便捷和高效的网络请求处理。 首先,OkHttp是一个开源的HTTP客户端,它能够处理网络请求、连接管理、请求重试等一系列的网络相关事务。它的特点是简单易用、性能优越、可定制性强。我们可以通过使用OkHttp来发送和接收基于HTTP的请求响应,并进行网络请求的管理和处理。 其次,RxJava是一个响应式编程框架,它基于观察者模式和函数式编程的思想,提供了一系列强大的操作符和线程切换的能力。我们可以使用RxJava来处理异步任务,加快网络请求的响应时间,并且提供方便的线程切换和错误处理机制。 最后,Retrofit是一个RESTful风格的网络请求框架,它结合了OkHttp和RxJava的强大功能。它提供了一种简单的方式来定义和处理RESTful API的请求和响应。我们可以使用Retrofit来创建和处理webservice的请求,根据API的接口定义来发送请求,并将返回的结果映射到Java对象中。 综上所述,使用OkHttp、RxJavaRetrofit能够方便地进行webservice的网络请求,并在处理过程中提供更好的性能和便利性。这三个库的结合能够大大简化网络请求的开发工作,提高开发效率,并提供更好的用户体验。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值