okHttp是相当于httpURLConnection、HttpClient同一级别的网络请求方式,而现在的httpURLConnection底层也是通过okHttp来实现的。因此square公司之前出了一个新的框架:Retrofit对okHttp近一步封装。
通常我们对网络数据进行请求,联网的时候返回数据,没有网络的时候则无法请求数据。这种效果其实对很多App来说不是很令人满意的。因此,我们希望在没有网络的时候,去调用请求,可以获得历史的缓存数据,这样的话,App也会显得更加人性化,更加的有可使用性。
Retrofit刚好很好的给我们提供了设置缓存的方法。
因为Retrofit是基于okHttp的,因此,它的缓存设置需要通过okHttp来实现。
在这里,给大家两种缓存设置的方法:
1、当请求网络超时,去读取缓存数据:
- private static final int TIMEOUT_CONNECT = 5; //5秒
- static final Interceptor REWRITE_RESPONSE_INTERCEPTOR = new Interceptor() {
- @Override
- public okhttp3.Response intercept(Chain chain) throws IOException {
- //获取retrofit @headers里面的参数,参数可以自己定义,在本例我自己定义的是cache,跟@headers里面对应就可以了
- String cache = chain.request().header("cache");
- okhttp3.Response originalResponse = chain.proceed(chain.request());
- String cacheControl = originalResponse.header("Cache-Control");
- //如果cacheControl为空,就让他TIMEOUT_CONNECT秒的缓存,本例是5秒,方便观察。注意这里的cacheControl是服务器返回的
- if (cacheControl == null) {
- //如果cache没值,缓存时间为TIMEOUT_CONNECT,有的话就为cache的值
- if (cache == null || "".equals(cache)) {
- cache = TIMEOUT_CONNECT + "";
- }
- originalResponse = originalResponse.newBuilder()
- .header("Cache-Control", "public, max-age=" + cache)
- .build();
- return originalResponse;
- } else {
- return originalResponse;
- }
- }
- };
private static final int TIMEOUT_CONNECT = 5; //5秒
static final Interceptor REWRITE_RESPONSE_INTERCEPTOR = new Interceptor() {
@Override
public okhttp3.Response intercept(Chain chain) throws IOException {
//获取retrofit @headers里面的参数,参数可以自己定义,在本例我自己定义的是cache,跟@headers里面对应就可以了
String cache = chain.request().header("cache");
okhttp3.Response originalResponse = chain.proceed(chain.request());
String cacheControl = originalResponse.header("Cache-Control");
//如果cacheControl为空,就让他TIMEOUT_CONNECT秒的缓存,本例是5秒,方便观察。注意这里的cacheControl是服务器返回的
if (cacheControl == null) {
//如果cache没值,缓存时间为TIMEOUT_CONNECT,有的话就为cache的值
if (cache == null || "".equals(cache)) {
cache = TIMEOUT_CONNECT + "";
}
originalResponse = originalResponse.newBuilder()
.header("Cache-Control", "public, max-age=" + cache)
.build();
return originalResponse;
} else {
return originalResponse;
}
}
};
2、当网络未连接时,直接去读取缓存数据:
- <span style="font-size:14px;"> private static final int TIMEOUT_DISCONNECT = 60 * 60 * 24 * 7; //7天
- static final Interceptor REWRITE_RESPONSE_INTERCEPTOR_OFFLINE = new Interceptor() {
- @Override
- public okhttp3.Response intercept(Chain chain) throws IOException {
- Request request = chain.request();
- //离线的时候为7天的缓存。
- if (JuMuApplication.isWorkingOffline()) {
- request = request.newBuilder()
- .header("Cache-Control", "public, only-if-cached, max-stale=" + TIMEOUT_DISCONNECT)
- .build();
- }
- return chain.proceed(request);
- }
- };</span>
private static final int TIMEOUT_DISCONNECT = 60 * 60 * 24 * 7; //7天
static final Interceptor REWRITE_RESPONSE_INTERCEPTOR_OFFLINE = new Interceptor() {
@Override
public okhttp3.Response intercept(Chain chain) throws IOException {
Request request = chain.request();
//离线的时候为7天的缓存。
if (JuMuApplication.isWorkingOffline()) {
request = request.newBuilder()
.header("Cache-Control", "public, only-if-cached, max-stale=" + TIMEOUT_DISCONNECT)
.build();
}
return chain.proceed(request);
}
};
使用方法:
首先设置OkhttpClient,为其添加拦截器,然后在设置Retrofit即可。
- <span style="font-size:14px;">private static Retrofit retrofit;
- private final static int SIZE_OF_CACHE = 10 * 1024 * 1024; // 10 MiB
- String cacheFile = context.getCacheDir() + "response_cache";
- Cache cache = new Cache(new File(cacheFile), SIZE_OF_CACHE);
- //利用okhttp实现缓存
- OkHttpClient client = new OkHttpClient.Builder()
- //有网络时的拦截器
- .addNetworkInterceptor(RetrofitCacheStrategy.REWRITE_RESPONSE_INTERCEPTOR)
- //没网络时的拦截器
- .addInterceptor(RetrofitCacheStrategy.REWRITE_RESPONSE_INTERCEPTOR_OFFLINE)
- .cache(cache)
- .build();
- retrofit = new Retrofit.Builder().client(client).baseUrl(BASE_URL).build();</span>
private static Retrofit retrofit;
private final static int SIZE_OF_CACHE = 10 * 1024 * 1024; // 10 MiB
String cacheFile = context.getCacheDir() + "response_cache";
Cache cache = new Cache(new File(cacheFile), SIZE_OF_CACHE);
//利用okhttp实现缓存
OkHttpClient client = new OkHttpClient.Builder()
//有网络时的拦截器
.addNetworkInterceptor(RetrofitCacheStrategy.REWRITE_RESPONSE_INTERCEPTOR)
//没网络时的拦截器
.addInterceptor(RetrofitCacheStrategy.REWRITE_RESPONSE_INTERCEPTOR_OFFLINE)
.cache(cache)
.build();
retrofit = new Retrofit.Builder().client(client).baseUrl(BASE_URL).build();
关于UnKnownHostException问题解决方法:
当我们首次就去没有网络读取数据的时候,Retrofit会去缓存读取,这时Retrofit认为是有数据可以请求的,但是因为是首次,本地并没有缓存,导致了我们请求服务器的时候,报了UnKnownHostException这个异常。关于这个问题,很多人也在github上面提过,而处理的方法就是直接try catch去避免异常。
当我们用RxJava + Retrofit的时候就更加方便了,我只有在doOnError里对异常进行trycatch或者直接,添加
避免所有异常即可,当然后者的方法太笼统了,可能会导致忽略了其他关键问题。.onErrorResumeNext(Flowable.<T>empty());