okHttp--Retrofit網(wǎng)絡(luò)緩存設(shè)置總結(jié)

轉(zhuǎn)載請標(biāo)明出處:http://www.reibang.com/p/241e6af94390
本文出自:Jlanglang

前言

找了些文章,發(fā)現(xiàn)說的都不是很清楚.設(shè)置始終有點(diǎn)問題
這個(gè)配置,每個(gè)人的需求不一樣,實(shí)現(xiàn)情況肯定也不一樣.
說說我的需求:
1.有網(wǎng)的時(shí)候所有接口不使用緩存
2.指定的接口產(chǎn)生緩存文件,其他接口不會產(chǎn)生緩存文件
3.無網(wǎng)的時(shí)候指定的接口使用緩存數(shù)據(jù).其他接口不使用緩存數(shù)據(jù)

1.網(wǎng)絡(luò)攔截器(關(guān)鍵)

提示:只能緩存Get請求

 Interceptor cacheInterceptor = new Interceptor() {
            @Override
            public Response intercept(Chain chain) throws IOException {
                //拿到請求體
                Request request = chain.request();

                //讀接口上的@Headers里的注解配置
                String cacheControl = request.cacheControl().toString();

                //判斷沒有網(wǎng)絡(luò)并且添加了@Headers注解,才使用網(wǎng)絡(luò)緩存.
                if (!Utils.isOpenInternet()&&!TextUtils.isEmpty(cacheControl)){
                    //重置請求體;
                    request = request.newBuilder()
                              //強(qiáng)制使用緩存
                            .cacheControl(CacheControl.FORCE_CACHE)
                            .build();
                }

             //如果沒有添加注解,則不緩存
                if (TextUtils.isEmpty(cacheControl) || "no-store" .contains(cacheControl)) {
                    //響應(yīng)頭設(shè)置成無緩存
                    cacheControl = "no-store";
                } else if (Utils.isOpenInternet()) {
                    //如果有網(wǎng)絡(luò),則將緩存的過期時(shí)間,設(shè)置為0,獲取最新數(shù)據(jù)
                    cacheControl = "public, max-age=" + 0;
                }else {
                    //...如果無網(wǎng)絡(luò),則根據(jù)@headers注解的設(shè)置進(jìn)行緩存.
                }
                Response response = chain.proceed(request);
                HLog.i("httpInterceptor", cacheControl);
                return response.newBuilder()
                        .header("Cache-Control", cacheControl)
                        .removeHeader("Pragma")
                        .build();
        };

具體接口中的使用,添加headers:

 /**
   * 只能緩存get請求.
   * 這里我設(shè)置了1天的緩存時(shí)間
   * 接口隨便寫的.哈哈,除了 @Headers(...),其它代碼沒啥參考價(jià)值.
   */
    @Headers("Cache-Control: public, max-age=" + 24 * 3600)
    @GET("url")
    Observable<?> queryInfo(@Query("userName") String userName);

關(guān)于Cache-Control頭的參數(shù)說明:

public  所有內(nèi)容都將被緩存(客戶端和代理服務(wù)器都可緩存)

private 內(nèi)容只緩存到私有緩存中(僅客戶端可以緩存抖韩,代理服務(wù)器不可緩存)

no-cache    no-cache是會被緩存的蛀恩,只不過每次在向客戶端(瀏覽器)提供響應(yīng)數(shù)據(jù)時(shí),緩存都要向服務(wù)器評估緩存響應(yīng)的有效性茂浮。 

no-store    所有內(nèi)容都不會被緩存到緩存或 Internet 臨時(shí)文件中

max-age=xxx (xxx is numeric)    緩存的內(nèi)容將在 xxx 秒后失效, 這個(gè)選項(xiàng)只在HTTP 1.1可用, 并如果和Last-Modified一起使用時(shí), 優(yōu)先級較高

max-stale和max-age一樣双谆,只能設(shè)置在請求頭里面。

同時(shí)設(shè)置max-stale和max-age励稳,緩存失效的時(shí)間按最長的算佃乘。(這個(gè)其實(shí)不用糾結(jié))

還有2個(gè)參數(shù):

CacheControl.FORCE_CACHE 強(qiáng)制使用緩存,如果沒有緩存數(shù)據(jù),則拋出504(only-if-cached)
CacheControl.FORCE_NETWORK 強(qiáng)制使用網(wǎng)絡(luò),不使用任何緩存.

這兩個(gè)設(shè)置,不會判斷是否有網(wǎng).需要自己寫判斷.
設(shè)置錯(cuò)誤會導(dǎo)致,數(shù)據(jù)不刷新,或者有網(wǎng)情況下,請求不到數(shù)據(jù)
這兩個(gè)很關(guān)鍵..可以根據(jù)自己的需求,進(jìn)行切換.

2.設(shè)置OkHttpClient

  OkHttpClient client = new OkHttpClient.Builder()
                //添加log攔截器,打印log信息,代碼后面貼出
                .addInterceptor(loggingInterceptor)
                //添加上面代碼的攔截器,設(shè)置緩存
                .addNetworkInterceptor(cacheInterceptor)
                //這個(gè)也要添加,否則無網(wǎng)的時(shí)候,緩存設(shè)置不會生效
                .addInterceptor(cacheInterceptor)
                //設(shè)置緩存目錄,以及最大緩存的大小,這里是設(shè)置10M
                .cache(new Cache(MyApplication.getContext().getCacheDir(), 10240 * 1024))
                .build();

3.完整的代碼:

public class RetrofitUtil {
    /**
     * 服務(wù)器地址
     */
    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();
                //有網(wǎng)的時(shí)候,讀接口上的@Headers里的注解配置
                String cacheControl = request.cacheControl().toString();
                //沒有網(wǎng)絡(luò)并且添加了注解,才使用緩存.
                if (!Utils.isOpenInternet()&&!TextUtils.isEmpty(cacheControl)){
                    //重置請求體;
                    request = request.newBuilder()
                            .cacheControl(CacheControl.FORCE_CACHE)
                            .build();
                }

             //如果沒有添加注解,則不緩存
                if (TextUtils.isEmpty(cacheControl) || "no-store" .contains(cacheControl)) {
                    //響應(yīng)頭設(shè)置成無緩存
                    cacheControl = "no-store";
                } else if (Utils.isOpenInternet()) {
                    //如果有網(wǎng)絡(luò),則將緩存的過期事件,設(shè)置為0,獲取最新數(shù)據(jù)
                    cacheControl = "public, max-age=" + 0;
                }else {
                    //...如果無網(wǎng)絡(luò),則根據(jù)@headers注解的設(shè)置進(jìn)行緩存.
                }
                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";
    }
}


交流群:493180098,這是個(gè)很少吹水,交流學(xué)習(xí)的群.
APP開發(fā)維護(hù)咨詢?nèi)?: 492685472 承接APP迭代.開發(fā)維護(hù).咨詢業(yè)務(wù),付費(fèi)快速解決問題.

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末驹尼,一起剝皮案震驚了整個(gè)濱河市趣避,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌新翎,老刑警劉巖程帕,帶你破解...
    沈念sama閱讀 216,651評論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異地啰,居然都是意外死亡愁拭,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,468評論 3 392
  • 文/潘曉璐 我一進(jìn)店門亏吝,熙熙樓的掌柜王于貴愁眉苦臉地迎上來岭埠,“玉大人,你說我怎么就攤上這事∠郏” “怎么了许赃?”我有些...
    開封第一講書人閱讀 162,931評論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長馆类。 經(jīng)常有香客問我混聊,道長,這世上最難降的妖魔是什么乾巧? 我笑而不...
    開封第一講書人閱讀 58,218評論 1 292
  • 正文 為了忘掉前任句喜,我火速辦了婚禮,結(jié)果婚禮上沟于,老公的妹妹穿的比我還像新娘咳胃。我一直安慰自己,他們只是感情好旷太,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,234評論 6 388
  • 文/花漫 我一把揭開白布拙绊。 她就那樣靜靜地躺著,像睡著了一般泳秀。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上榄攀,一...
    開封第一講書人閱讀 51,198評論 1 299
  • 那天嗜傅,我揣著相機(jī)與錄音,去河邊找鬼檩赢。 笑死吕嘀,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的贞瞒。 我是一名探鬼主播偶房,決...
    沈念sama閱讀 40,084評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼军浆!你這毒婦竟也來了棕洋?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 38,926評論 0 274
  • 序言:老撾萬榮一對情侶失蹤乒融,失蹤者是張志新(化名)和其女友劉穎掰盘,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體赞季,經(jīng)...
    沈念sama閱讀 45,341評論 1 311
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡愧捕,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,563評論 2 333
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了申钩。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片次绘。...
    茶點(diǎn)故事閱讀 39,731評論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出邮偎,到底是詐尸還是另有隱情管跺,我是刑警寧澤,帶...
    沈念sama閱讀 35,430評論 5 343
  • 正文 年R本政府宣布钢猛,位于F島的核電站伙菜,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏命迈。R本人自食惡果不足惜贩绕,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,036評論 3 326
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望壶愤。 院中可真熱鬧淑倾,春花似錦、人聲如沸征椒。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,676評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽勃救。三九已至碍讨,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,829評論 1 269
  • 我被黑心中介騙來泰國打工奠支, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人覆获。 一個(gè)月前我還...
    沈念sama閱讀 47,743評論 2 368
  • 正文 我出身青樓,卻偏偏與公主長得像瓢省,于是被迫代替她去往敵國和親弄息。 傳聞我的和親對象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,629評論 2 354

推薦閱讀更多精彩內(nèi)容

  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理勤婚,服務(wù)發(fā)現(xiàn)摹量,斷路器,智...
    卡卡羅2017閱讀 134,652評論 18 139
  • 參考Android網(wǎng)絡(luò)請求心路歷程Android Http接地氣網(wǎng)絡(luò)請求(HttpURLConnection) 一...
    合肥黑閱讀 21,274評論 7 63
  • 本文就是講解在OKHTTP中如何配置緩存蛔六。 HTTP協(xié)議中緩存相關(guān) 為了更好的講解OKHTTP怎么設(shè)置緩存荆永,我們追...
    TendaZhang閱讀 3,033評論 7 19
  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 172,079評論 25 707
  • 1.我覺得我的元認(rèn)知能力不強(qiáng)。在思考別人的情感問題的時(shí)候国章,感覺自己的元認(rèn)知能力特別強(qiáng)…… 2.在學(xué)習(xí)時(shí)具钥;在應(yīng)對突發(fā)...
    洛尓閱讀 128評論 0 0