使用Retrofit 2和okhttp 3缓存错误

时间:2017-01-10 16:36:18

标签: android caching retrofit2 okhttp3 offline-caching

我正在尝试从我的公司API缓存HTTP响应,但看起来该应用无法访问缓存目录:

  

W / System.err:删除失败:ENOENT(没有这样的文件或目录):   /data/user/0/com.appname/cache/cache_file/journal.tmp

     

W / System.err的:   java.net.UnknownHostException:无法解析主机   “www.domain.com”:没有与主机名相关联的地址

我已关注此tutorial。以下是我设置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);
    }
}

我尝试了一些通过互联网和stackoverflow找到的解决方案(仍然在上面的代码中发表评论),因为起初我认为这是一个“缓存控制”重写问题。

我还在清单中添加了READ_EXTERNAL_STORAGE和WRITE_EXTERNAL_STORAGE权限,但它不会改变任何内容。

我错过了什么吗? (我正在使用Android 6.0.1 API测试三星)

2 个答案:

答案 0 :(得分:0)

您可能错过了清单中的INTERNET权限。

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

这是导致UnknownHostException错误的常见原因。

或者,请确保您可以通过在浏览器中访问该网站来实际访问该设备上的网站

答案 1 :(得分:0)

关于第一个错误,让我们看看为OkHttpClient提供的缓存目录:

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

您已经为许多OkHttpClient使用了相同的缓存目录,许多实例可能会互相攻击,从而破坏响应缓存。 要解决此问题,您可以使用OkHttpClient一次,使用其缓存进行配置,并在任何地方使用相同的实例。你可以尝试如下:

    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();

有关使用OkHttpClient进行缓存的更多信息,您可以查看this link