サーバーからデータをリクエストするために、retrofit 2とOkHttp3を使用しています。オフラインキャッシュコードを追加しましたが、期待どおりに動作しません。 「ホスト "<>"を解決できません:ホスト名に関連付けられたアドレスがありません。」というエラーが表示されました。
これは、キャッシュから取得データを取得しようとしたときに発生します(インターネット接続がない場合)。コードスニペットは次のとおりです。
public static Interceptor provideCacheInterceptor() {
return new Interceptor() {
@Override
public Response intercept(Chain chain) throws IOException {
Response response = chain.proceed(chain.request());
// re-write response header to force use of cache
CacheControl cacheControl = new CacheControl.Builder()
.maxAge(2, TimeUnit.MINUTES)
.build();
return response.newBuilder()
.header(CACHE_CONTROL, cacheControl.toString())
.build();
}
};
}
public static Interceptor provideOfflineCacheInterceptor() {
return new Interceptor() {
@Override
public Response intercept(Chain chain) throws IOException {
Request request = chain.request();
if (!hasNetwork) {
CacheControl cacheControl = new CacheControl.Builder()
.onlyIfCached()
.maxStale(7, TimeUnit.DAYS)
.build();
request = request.newBuilder()
.removeHeader("Pragma")
.cacheControl(cacheControl)
.build();
}
return chain.proceed(request);
}
};
}
private static Cache provideCache() {
Cache cache = null;
try {
cache = new Cache(new File(AdeptAndroid.getInstance().getCacheDir(), "http-cache"),
10 * 1024 * 1024); // 10 MB
} catch (Exception e) {
Log.d("Test", "Could not create Cache!");
}
return cache;
}
そして最後に、これらすべてを組み合わせる方法がここにあります。
private static OkHttpClient provideOkHttpClient() {
return new OkHttpClient.Builder()
.addInterceptor(provideHttpLoggingInterceptor())
.addInterceptor(provideOfflineCacheInterceptor())
.addNetworkInterceptor(provideCacheInterceptor())
.cache(provideCache())
.build();
}
Kotlinを使用したプロジェクトでも同じエラーが発生し、次のように修正しました。
client.addInterceptor(provideOfflineCacheInterceptor(context))
client.addNetworkInterceptor(provideCacheInterceptor(context))
private fun provideOfflineCacheInterceptor(context: Context): Interceptor {
return Interceptor { chain ->
var request = chain.request()
var cacheHeaderValue = if (!hasNetwork(context)!!){
"public, only-if-cached, max-stale=" + 60 * 60 * 24 * 1
} else {
"public, max-age=" + 5
}
request = request.newBuilder().header("Cache-Control", cacheHeaderValue).build()
chain.proceed(request)
}
}
private fun provideCacheInterceptor(context: Context): Interceptor {
return Interceptor { chain ->
val request = chain.request()
var cacheHeaderValue = if (!hasNetwork(context)!!){
"public, only-if-cached, max-stale=" + 60 * 60 * 24 * 1
} else {
"public, max-age=" + 5
}
//request = request.newBuilder().build()
val response = chain.proceed(request)
response.newBuilder()
.removeHeader("Pragma")
.removeHeader("Cache-Control")
.header("Cache-Control", cacheHeaderValue)
.build()
}
}
これは、接続されたネットワークで利用できないホスト名にアクセスしようとしたときに発生します。デバイスのWebブラウザーからこのURLにアクセスできるかどうかを確認してください。そうでない場合:問題があります。
サーバーの応答に「Pragma:no-cache」ヘッダーがあります。このヘッダーは、リクエストインターセプターではなく、レスポンスインターセプターで削除する必要があります。
現在のコードでは、リクエストインターセプターからコードを削除しています。
provideCacheInterceptor()
は次のようになります。
public static Interceptor provideCacheInterceptor() {
return new Interceptor() {
@Override
public Response intercept(Chain chain) throws IOException {
Response response = chain.proceed(chain.request());
// re-write response header to force use of cache
CacheControl cacheControl = new CacheControl.Builder()
.maxAge(2, TimeUnit.MINUTES)
.build();
return response.newBuilder()
.header(CACHE_CONTROL, cacheControl.toString())
.removeHeader("Pragma")
.build();
}
};
}
エミュレータの機内モードをオフにして、マニフェストファイルのアクセス許可でネットワークを「オンにする」を確認してください