轉(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)快速解決問題.