Caching error using Retrofit 2 and okhttp 3

I am trying to cache HTTP responses from my company’s API, but it looks like the application cannot access the cache directory:

W / System.err: could not be deleted: ENOENT (There is no such file or directory): / data / user / 0 / com.appname / cache / cache_file / journal.tmp

Tue / System.err: java.net.UnknownHostException: cannot resolve host "www.domain.com": no address associated with host name

I followed this tutorial . This is how I configure Retrofit (2.1.0):

import lu.CompanyName.R; import lu.CompanyName.interfaces.CompanyNameAPI; import okhttp3.Cache; import okhttp3.Interceptor; import okhttp3.OkHttpClient; import okhttp3.Request; import okhttp3.Response; import okhttp3.logging.HttpLoggingInterceptor; import retrofit2.Retrofit; import retrofit2.converter.gson.GsonConverterFactory; import static okhttp3.logging.HttpLoggingInterceptor.Level.HEADERS; public class Injector { private static final String CACHE_CONTROL = "Cache-Control"; private static Retrofit provideRetrofit (String baseUrl) { return new Retrofit.Builder() .baseUrl(baseUrl) .client(provideOkHttpClient()) .addConverterFactory(GsonConverterFactory.create()) .build(); } private static OkHttpClient provideOkHttpClient () { return new OkHttpClient.Builder() .addInterceptor(provideHttpLoggingInterceptor()) .addInterceptor(provideOfflineCacheInterceptor()) .addNetworkInterceptor(provideCacheInterceptor()) .cache(provideCache()) .build(); } private static Cache provideCache () { /* Cache cache = null; try { File dir = CompanyName.getInstance().getExternalCacheDir(); if (dir == null) dir = CompanyName.getInstance().getCacheDir(); if (dir == null) Log.e("provideCache", "dir is null"); cache = new Cache(new File(dir, "http-cache"), 10 * 1024 * 1024); // 10 MB if (cache == null) Log.e("provideCache", "cache is null"); } catch (Exception e) { Log.e("provideCache", "Could not create Cache!"); } return cache;*/ /* File httpCacheDirectory = new File(CompanyName.getInstance().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("provideCache", "URLs in cacheHttpClient : "); while (iterator.hasNext()) { Log.i("provideCache", iterator.next()); } } catch (IOException e) { e.printStackTrace(); Log.i("provideCache", "CACHE NOT INIT"); } return cache;*/ return new Cache(new File(CompanyName.getInstance().getCacheDir(), "cache_file"), 20 * 1024 * 1024); } private static HttpLoggingInterceptor provideHttpLoggingInterceptor () { HttpLoggingInterceptor httpLoggingInterceptor = new HttpLoggingInterceptor(); httpLoggingInterceptor.setLevel(HEADERS); return httpLoggingInterceptor; } private 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.HOURS) .build(); return response.newBuilder() .header(CACHE_CONTROL, cacheControl.toString()) .build(); } };*/ return new Interceptor() { @Override public Response intercept(Chain chain) throws IOException { Request originalRequest = chain.request(); String cacheHeaderValue = CompanyName.getInstance().checkIfHasNetwork() ? "public, max-age=2419200" : "public, only-if-cached, max-stale=2419200" ; Request request = originalRequest.newBuilder().build(); Response response = chain.proceed(request); return response.newBuilder() .removeHeader("Pragma") .removeHeader("Cache-Control") .header("Cache-Control", cacheHeaderValue) .build(); } }; } private static Interceptor provideOfflineCacheInterceptor () { /*return new Interceptor() { @Override public Response intercept (Chain chain) throws IOException { Request request = chain.request(); if (!CompanyName.hasNetwork()) { CacheControl cacheControl = new CacheControl.Builder() //.maxStale(7, TimeUnit.DAYS) .build(); request = request.newBuilder() .cacheControl(cacheControl) .build(); } return chain.proceed(request); } };*/ return new Interceptor() { @Override public Response intercept(Chain chain) throws IOException { Request originalRequest = chain.request(); String cacheHeaderValue = CompanyName.getInstance().checkIfHasNetwork() ? "public, max-age=2419200" : "public, only-if-cached, max-stale=2419200" ; Request request = originalRequest.newBuilder().build(); Response response = chain.proceed(request); return response.newBuilder() .removeHeader("Pragma") .removeHeader("Cache-Control") .header("Cache-Control", cacheHeaderValue) .build(); } }; } public static CompanyNameAPI provideCompanyNameAPI () { return provideRetrofit(CompanyName.getInstance().getString(R.string.base_url)).create(CompanyNameAPI.class); } } 

I tried some solutions found over the internet and stackoverflow (still in the comments in the code above), because at first I thought it was a problem with rewriting "Cache-Control".

I also added READ_EXTERNAL_STORAGE and WRITE_EXTERNAL_STORAGE permissions to the manifest, but didn't change anything.

Did I miss something? (I am testing on Samsung with Android 6.0.1 API 23)

+2
source share
2 answers

The manifest may not have INTERNET permission.

<uses-permission android:name="android.permission.INTERNET" />

This is a common reason for getting UnknownHostException errors.

Also, make sure that you can actually connect to the site on this device by visiting the site in a browser.

0
source

As for the first error, see the cache directory for OkHttpClient:

  private static OkHttpClient provideOkHttpClient () { return new OkHttpClient.Builder() .addInterceptor(provideHttpLoggingInterceptor()) .addInterceptor(provideOfflineCacheInterceptor()) .addNetworkInterceptor(provideCacheInterceptor()) .cache(provideCache()) .build(); } 

You used the same cache directory for many OkHttpClient, many instances can stomp on each other, damage the response cache. To fix this, you can use OkHttpClient exactly once, configure it with your cache, and use the same instance everywhere. You can try the following:

  private static Retrofit provideRetrofit (String baseUrl) { return new Retrofit.Builder() .baseUrl(baseUrl) .client(okHttpClient) .addConverterFactory(GsonConverterFactory.create()) .build(); } private static OkHttpClient okHttpClient = new OkHttpClient.Builder() .addInterceptor(provideHttpLoggingInterceptor()) .addInterceptor(provideOfflineCacheInterceptor()) .addNetworkInterceptor(provideCacheInterceptor()) .cache(provideCache()) .build(); 

For more information about the cache with OkHttpClient you can see this link .

0
source

Source: https://habr.com/ru/post/1259556/


All Articles