Gor*_*dak 5 android caching retrofit2 okhttp3
我正在尝试使用Retrofit(2.1.0)和OkHttp(3.3.1)设置HTTP缓存.我见过很多与此主题相关的帖子,但没有一个有用.
我写了一些单元测试来查看缓存是如何工作的.它工作正常,但一旦集成在我的应用程序中,魔术就结束了.我将首先向您展示我的实施,然后解释我的一些调查.
首先,这是我的Retrofit实例化:
OkHttpClient.Builder httpBuilder = new OkHttpClient.Builder();
HttpLoggingInterceptor loggingInterceptor = new HttpLoggingInterceptor();
interceptor.setLevel(HttpLoggingInterceptor.Level.HEADERS);
OkHttpClient client = httpBuilder
.addNetworkInterceptor(INTERCEPTOR_RESPONSE_SET_CACHE)
.addNetworkInterceptor(INTERCEPTOR_REQUEST_ADD_CHECKSUM)
.addInterceptor(loggingInterceptor)
.cache(cacheHttpClient).build();
Retrofit retrofit = new Retrofit.Builder()
.addConverterFactory(GsonConverterFactory.create())
.client(client)
.baseUrl(BASE_URL)
.build();
Run Code Online (Sandbox Code Playgroud)
这是拦截器添加标头来设置缓存控件:
private final Interceptor INTERCEPTOR_RESPONSE_SET_CACHE = new Interceptor() {
@Override
public Response intercept(Chain chain) throws IOException {
Response response = chain.proceed(chain.request());
response = response.newBuilder()
.header("Cache-Control", "max-age=600") //+ Integer.toString(3600 * 5)
.build();
return response;
}
};
Run Code Online (Sandbox Code Playgroud)
最后一个拦截器添加了2个URL参数:
private static final Interceptor INTERCEPTOR_REQUEST_ADD_CHECKSUM = new Interceptor() {
@Override
public Response intercept(Interceptor.Chain chain) throws IOException {
HttpUrl url = chain.request().url();
url = url.newBuilder().addQueryParameter("rd", "random1").addQueryParameter("chk","check1").build();
Request request = chain.request().newBuilder().url(url).build();
return chain.proceed(request);
}
};
Run Code Online (Sandbox Code Playgroud)
最后,我的服务的单一方法:
@Headers("Cache-Control: public, max-stale=500")
@GET("/get_data")
Call<DataResponse> getData(@Query("year") int year, @Query("month") int month, @Query("day") int day);
Run Code Online (Sandbox Code Playgroud)
关于我的调查,我设置了一个拦截器记录器(应用程序端,而不是网络)来查看发生了什么.我可以在日志中看到诸如"Cache-Control:public,max-stale = 500"之类的行.这意味着(至少对我而言)标题应该为OkHttp客户端提供检查缓存的机会.
缓存本身似乎已正确初始化.当我创建它时,我强制初始化并记录缓存中存在的所有URL.以下是它的实现方式:
File httpCacheDirectory = new File(getCacheDir(), "responses");
httpCacheDirectory.getParentFile().mkdirs();
int cacheSize = 10 * 1024 * 1024; // 10 MiB
Cache cache = new Cache(httpCacheDirectory, cacheSize);
try {
cache.initialize();
Iterator<String> iterator = cache.urls();
Log.i(TAG, "URLs in cacheHttpClient : ");
while (iterator.hasNext()) {
Log.i(TAG, iterator.next());
}
} catch (IOException e) {
e.printStackTrace();
Log.i(TAG, "CACHE NOT INIT");
}
Run Code Online (Sandbox Code Playgroud)
当我使用Wifi启动我的应用程序时,我得到了预期的响应.然后我杀了我的应用程序,禁用Wifi并重新启动应用程序.我希望此时缓存能够提供数据.但它失败了,我只能在日志中看到OkHttp打印的行:
HTTP FAILED:java.net.UnknownHostException:无法解析主机"my-domain.com":没有与主机名关联的地址
最后,在RFC 2616中,可以阅读:
max-stale:表示客户端愿意接受超过其到期时间的响应.如果为max-stale分配了值,则客户端愿意接受超过其到期时间的响应不超过指定的秒数.如果没有为max-stale分配值,则客户愿意接受任何年龄的陈旧响应.
当我没有指定一个值时,它实际上是有效的(即使在Wifi关闭时我也会得到响应).现在,这是我发现让它"工作"的唯一方法.所以也许我只是误解了缓存控制指令!
此时我真的很困惑.我真的希望能够使用OkHttp缓存系统,但不知怎的,我错过了一些东西.
感谢您阅读所有文字!
使用该方法创建缓存的okkhttpclient
private OkHttpClient createCachedClient(final Context context) {
File httpCacheDirectory = new File(context.getCacheDir(), "cache_file");
Cache cache = new Cache(httpCacheDirectory, 20 * 1024 * 1024);
OkHttpClient okHttpClient = new OkHttpClient();
okHttpClient.setCache(cache);
okHttpClient.interceptors().add(
new Interceptor() {
@Override
public com.squareup.okhttp.Response intercept(Chain chain) throws IOException {
Request originalRequest = chain.request();
String cacheHeaderValue = isOnline(context)
? "public, max-age=2419200"
: "public, only-if-cached, max-stale=2419200" ;
Request request = originalRequest.newBuilder().build();
com.squareup.okhttp.Response response = chain.proceed(request);
return response.newBuilder()
.removeHeader("Pragma")
.removeHeader("Cache-Control")
.header("Cache-Control", cacheHeaderValue)
.build();
}
}
);
okHttpClient.networkInterceptors().add(
new Interceptor() {
@Override
public com.squareup.okhttp.Response intercept(Chain chain) throws IOException {
Request originalRequest = chain.request();
String cacheHeaderValue = isOnline(context)
? "public, max-age=2419200"
: "public, only-if-cached, max-stale=2419200" ;
Request request = originalRequest.newBuilder().build();
com.squareup.okhttp.Response response = chain.proceed(request);
return response.newBuilder()
.removeHeader("Pragma")
.removeHeader("Cache-Control")
.header("Cache-Control", cacheHeaderValue)
.build();
}
}
);
return okHttpClient;
}
private boolean isOnline(Context context) {
ConnectivityManager connectivity = (ConnectivityManager) _context.getSystemService(Context.CONNECTIVITY_SERVICE);
if (connectivity != null) {
NetworkInfo[] info = connectivity.getAllNetworkInfo();
if (info != null)
for (int i = 0; i < info.length; i++)
if (info[i].getState() == NetworkInfo.State.CONNECTED) {
return true;
}
}
return false;
}
Run Code Online (Sandbox Code Playgroud)
调用 createCachedClient() 方法创建 OkHttpClient 添加此客户端进行改造
OkHttpClient okHttpClient = createCachedClient(MainActivity.this);
Retrofit retrofit=new Retrofit.Builder()
.client(okHttpClient)
.baseUrl(API)
.addConverterFactory(GsonConverterFactory
.create()).build();
Run Code Online (Sandbox Code Playgroud)
将此权限添加到清单中
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
Run Code Online (Sandbox Code Playgroud)
如果互联网第一次可用,它将调用服务并缓存请求,下次从 2419200 毫秒开始,它将使用缓存来给出响应。即使设备离线,它也不会在 2419200 毫秒内命中服务器。
归档时间: |
|
查看次数: |
909 次 |
最近记录: |