使用 Retrofit 2.0 和 okhttp3 进行缓存
Caching with Retrofit 2.0 and okhttp3
我正在尝试使用 Retrofit 和 OkHttp 实现缓存。这是我已经完成的:
private static final Interceptor REWRITE_CACHE_CONTROL_INTERCEPTOR = new Interceptor() {
@Override public Response intercept(Interceptor.Chain chain) throws IOException {
Request originalRequest = chain.request();
Request.Builder request = originalRequest.newBuilder();
Response response = chain.proceed(request.build());
return response.newBuilder()
.removeHeader("Pragma")
.removeHeader("Cache-Control")
.header("Cache-Control", "max-age=2419200")
.build();
}
};
@Provides
@Singleton
OkHttpClient provideHttpClient(Context context) {
File httpCacheDirectory = new File(context.getCacheDir(), "responses");
int cacheSize = 10 * 1024 * 1024; // 10 MiB
Cache cache = new Cache(httpCacheDirectory, cacheSize);
HttpLoggingInterceptor oggingInterceptor = new HttpLoggingInterceptor();
oggingInterceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
return new OkHttpClient.Builder()
.cache(cache)
.connectTimeout(3, TimeUnit.SECONDS)
.writeTimeout(3, TimeUnit.SECONDS)
.readTimeout(3, TimeUnit.SECONDS)
.addInterceptor(REWRITE_CACHE_CONTROL_INTERCEPTOR)
.addInterceptor(oggingInterceptor).build();
}
然后我将这个拦截器添加到 HTTP 客户端:
.addInterceptor(REWRITE_CACHE_CONTROL_INTERCEPTOR)
我的 responses 目录中有文件,但是当我尝试在没有互联网连接的情况下加载内容时,出现以下错误:
Unable to resolve host "example.com": No address associated with hostname
我只想将我的 http 响应存储在某处,并在没有互联网连接时加载它。
如果有互联网连接,我想重写缓存。
以这种方式设置 header(恰好 50000)解决了这个问题。
.header("Cache-Control", String.format("max-age=%d", 50000))
我和你遇到了同样的问题,现在我找到一篇文章解决了我的问题,我认为它可以帮助你。
因为在获取缓存的时候,okhttp会清空缓存重新请求服务器,此时缓存为空,所以会发送错误Exception。
我们可以使用您的拦截器进行一些请求设置。
CacheControl.Builder cacheBuilder = new CacheControl.Builder();
cacheBuilder.maxAge(0, TimeUnit.SECONDS);
cacheBuilder.maxStale(365,TimeUnit.DAYS);
CacheControl cacheControl = cacheBuilder.build();
Request request = chain.request();
if(!StateUtils.isNetworkAvailable(MyApp.mContext)){
request = request.newBuilder()
.cacheControl(cacheControl)
.build();
}
maxAge : 控制缓存最大生命周期
maxStale : 控制缓存过期时间
完整代码:
weiBoApiRetrofit() {
File httpCacheDirectory = new File(MyApp.mContext.getCacheDir(), "responses");
int cacheSize = 10 * 1024 * 1024; // 10 MiB
Cache cache = new Cache(httpCacheDirectory, cacheSize);
OkHttpClient client = new OkHttpClient.Builder()
.addNetworkInterceptor(REWRITE_CACHE_CONTROL_INTERCEPTOR)
.cache(cache).build();
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(BASE_URL)
.client(client)
.addConverterFactory(GsonConverterFactory.create())
.addCallAdapterFactory(RxJavaCallAdapterFactory.create())
.build();
WeiBoApiService = retrofit.create(WeiBoApi.class);
}
//cache
Interceptor REWRITE_CACHE_CONTROL_INTERCEPTOR = new Interceptor() {
@Override
public Response intercept(Chain chain) throws IOException {
CacheControl.Builder cacheBuilder = new CacheControl.Builder();
cacheBuilder.maxAge(0, TimeUnit.SECONDS);
cacheBuilder.maxStale(365,TimeUnit.DAYS);
CacheControl cacheControl = cacheBuilder.build();
Request request = chain.request();
if(StateUtils.isNetworkAvailable(MyApp.mContext)){
request = request.newBuilder()
.cacheControl(cacheControl)
.build();
}
Response originalResponse = chain.proceed(request);
if (StateUtils.isNetworkAvailable(MyApp.mContext)) {
int maxAge = 60 * 60; // read from cache
return originalResponse.newBuilder()
.header("Cache-Control", "public, max-age=" + maxAge)
.build();
} else {
int maxStale = 60 * 60 * 24 * 28; // tolerate 4-weeks stale
return originalResponse.newBuilder()
.header("Cache-Control", "public, only-if-cached, max-stale=" + maxStale)
.build();
}
}
};
}
我可以解决我的问题。
但是我不知道为什么拦截器的响应设置header没用,有人说“拦截器必须设置设置那两个请求和响应”
希望能帮到你。
我正在尝试使用 Retrofit 和 OkHttp 实现缓存。这是我已经完成的:
private static final Interceptor REWRITE_CACHE_CONTROL_INTERCEPTOR = new Interceptor() {
@Override public Response intercept(Interceptor.Chain chain) throws IOException {
Request originalRequest = chain.request();
Request.Builder request = originalRequest.newBuilder();
Response response = chain.proceed(request.build());
return response.newBuilder()
.removeHeader("Pragma")
.removeHeader("Cache-Control")
.header("Cache-Control", "max-age=2419200")
.build();
}
};
@Provides
@Singleton
OkHttpClient provideHttpClient(Context context) {
File httpCacheDirectory = new File(context.getCacheDir(), "responses");
int cacheSize = 10 * 1024 * 1024; // 10 MiB
Cache cache = new Cache(httpCacheDirectory, cacheSize);
HttpLoggingInterceptor oggingInterceptor = new HttpLoggingInterceptor();
oggingInterceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
return new OkHttpClient.Builder()
.cache(cache)
.connectTimeout(3, TimeUnit.SECONDS)
.writeTimeout(3, TimeUnit.SECONDS)
.readTimeout(3, TimeUnit.SECONDS)
.addInterceptor(REWRITE_CACHE_CONTROL_INTERCEPTOR)
.addInterceptor(oggingInterceptor).build();
}
然后我将这个拦截器添加到 HTTP 客户端:
.addInterceptor(REWRITE_CACHE_CONTROL_INTERCEPTOR)
我的 responses 目录中有文件,但是当我尝试在没有互联网连接的情况下加载内容时,出现以下错误:
Unable to resolve host "example.com": No address associated with hostname
我只想将我的 http 响应存储在某处,并在没有互联网连接时加载它。
如果有互联网连接,我想重写缓存。
以这种方式设置 header(恰好 50000)解决了这个问题。
.header("Cache-Control", String.format("max-age=%d", 50000))
我和你遇到了同样的问题,现在我找到一篇文章解决了我的问题,我认为它可以帮助你。
因为在获取缓存的时候,okhttp会清空缓存重新请求服务器,此时缓存为空,所以会发送错误Exception。
我们可以使用您的拦截器进行一些请求设置。
CacheControl.Builder cacheBuilder = new CacheControl.Builder();
cacheBuilder.maxAge(0, TimeUnit.SECONDS);
cacheBuilder.maxStale(365,TimeUnit.DAYS);
CacheControl cacheControl = cacheBuilder.build();
Request request = chain.request();
if(!StateUtils.isNetworkAvailable(MyApp.mContext)){
request = request.newBuilder()
.cacheControl(cacheControl)
.build();
}
maxAge : 控制缓存最大生命周期
maxStale : 控制缓存过期时间
完整代码:
weiBoApiRetrofit() {
File httpCacheDirectory = new File(MyApp.mContext.getCacheDir(), "responses");
int cacheSize = 10 * 1024 * 1024; // 10 MiB
Cache cache = new Cache(httpCacheDirectory, cacheSize);
OkHttpClient client = new OkHttpClient.Builder()
.addNetworkInterceptor(REWRITE_CACHE_CONTROL_INTERCEPTOR)
.cache(cache).build();
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(BASE_URL)
.client(client)
.addConverterFactory(GsonConverterFactory.create())
.addCallAdapterFactory(RxJavaCallAdapterFactory.create())
.build();
WeiBoApiService = retrofit.create(WeiBoApi.class);
}
//cache
Interceptor REWRITE_CACHE_CONTROL_INTERCEPTOR = new Interceptor() {
@Override
public Response intercept(Chain chain) throws IOException {
CacheControl.Builder cacheBuilder = new CacheControl.Builder();
cacheBuilder.maxAge(0, TimeUnit.SECONDS);
cacheBuilder.maxStale(365,TimeUnit.DAYS);
CacheControl cacheControl = cacheBuilder.build();
Request request = chain.request();
if(StateUtils.isNetworkAvailable(MyApp.mContext)){
request = request.newBuilder()
.cacheControl(cacheControl)
.build();
}
Response originalResponse = chain.proceed(request);
if (StateUtils.isNetworkAvailable(MyApp.mContext)) {
int maxAge = 60 * 60; // read from cache
return originalResponse.newBuilder()
.header("Cache-Control", "public, max-age=" + maxAge)
.build();
} else {
int maxStale = 60 * 60 * 24 * 28; // tolerate 4-weeks stale
return originalResponse.newBuilder()
.header("Cache-Control", "public, only-if-cached, max-stale=" + maxStale)
.build();
}
}
};
}
我可以解决我的问题。
但是我不知道为什么拦截器的响应设置header没用,有人说“拦截器必须设置设置那两个请求和响应”
希望能帮到你。