改造OKHTTP脱机缓存不起作用 [英] Retrofit OKHTTP Offline caching not working

查看:116
本文介绍了改造OKHTTP脱机缓存不起作用的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我阅读了许多教程和Stackoverflow回答了我的问题,但没有任何帮助!另外,它们大多数都是旧的,所以OKHTTP可能有所更改.

I read dozens of tutorial and Stackoverflow answers to my problem but nothing is working for me! Also, most of them are old so probably OKHTTP changed somehow.

我要做的就是为改造启用离线缓存.

All I want is to enable offline caching for Retrofit.

我正在使用GET

我尝试仅使用offlineCacheInterceptor作为拦截器,但是我一直得到:

I tried using only offlineCacheInterceptor as an Interceptor, but I kept getting:

Unable to resolve host "jsonplaceholder.typicode.com": No address associated with hostname

我尝试使用offlineCacheInterceptor作为拦截器+ provideCacheInterceptor()作为NetworkInterceptor的组合,但是我一直得到:

I tried using a combination of offlineCacheInterceptoras an Interceptor + provideCacheInterceptor() as a NetworkInterceptor, but I kept getting:

504 Unsatisfiable Request (only-if-cached) and a null response.body()

我什至确保在所有地方添加.removeHeader("Pragma")

I even made sure to add .removeHeader("Pragma") everywhere!

我尝试了所有这些链接:

I tried all these Links:

https://newfivefour.com/android-retrofit2- okhttp3-cache-network-request-offline.html (一个拦截器,不起作用!)

https://newfivefour.com/android-retrofit2-okhttp3-cache-network-request-offline.html (One interceptor, Not working!!)

https://medium.com/mindorks/caching- with-retrofit-store-responses-offline-71439ed32fda (一个拦截器,不起作用!)

https://medium.com/mindorks/caching-with-retrofit-store-responses-offline-71439ed32fda (One interceptor, Not working!)

https://caster.io/lessons/retrofit-2-offline-cache (单独的联机+脱机缓存,不起作用)

https://caster.io/lessons/retrofit-2-offline-cache (Separate Online + Offline caching, Not working)

https://www.journaldev.com/23297/android- retrofit-okhttp-offline-caching (不起作用,504个无法满足的请求(仅在已缓存的情况下))

https://www.journaldev.com/23297/android-retrofit-okhttp-offline-caching (Not working, 504 Unsatisfiable Request (only-if-cached))

http://mikescamell.com/gotcha-when-offline-caching -with-okhttp3/(一个拦截器,不起作用!)

http://mikescamell.com/gotcha-when-offline-caching-with-okhttp3/ (One interceptor, Not working!!)

https://stackoverflow.com/a/48295397/8086424 (无效) 无法解析主机"jsonplaceholder.typicode.com":没有与主机名关联的地址

https://stackoverflow.com/a/48295397/8086424 (Not Working) Unable to resolve host "jsonplaceholder.typicode.com": No address associated with hostname

可以使用OKHttp进行改造,离线时使用缓存数据(太令人困惑了!)

这是我的代码:

public static Retrofit getRetrofitInstance(Context context) {
        if (retrofit == null) {
            c = context;
            int cacheSize = 10 * 1024 * 1024; // 10 MB
            Cache cache = new Cache(context.getCacheDir(), cacheSize);
            OkHttpClient okHttpClient = new OkHttpClient.Builder()
                    .addInterceptor(provideHttpLoggingInterceptor())
                    .addInterceptor(offlineCacheInterceptor)
                    .addNetworkInterceptor(provideCacheInterceptor())
                    .cache(cache)
                    .build();
            //////////////////////////
            retrofit = new retrofit2.Retrofit.Builder()
                    .baseUrl(BASE_URL)
                    .addConverterFactory(GsonConverterFactory.create())
                    .client(okHttpClient)
                    .build();
        }
        return retrofit;
    }


 public static Interceptor offlineCacheInterceptor = new Interceptor() {
        @Override
        public Response intercept(Chain chain) throws IOException {
            Request request = chain.request();
            Log.e("bbbb", "bbbb");
            if (!checkInternetAvailability()) {
                Log.e("aaaaa", "aaaaaa");
                CacheControl cacheControl = new CacheControl.Builder()
                        .maxStale(30, TimeUnit.DAYS)
                        .build();

                request = request.newBuilder()
                        .cacheControl(cacheControl)
                        .removeHeader("Pragma")
                        .build();
            }
            return chain.proceed(request);
        }
    };


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


我正在使用jsonplaceholder.typicode.com/photos返回:


I am using jsonplaceholder.typicode.com/photos that returns:

content-type: application/json; charset=utf-8
    date: Sun, 21 Oct 2018 14:26:41 GMT
    set-cookie: __cfduid=d9e935012d2f789245b1e2599a41e47511540132001; expires=Mon, 21-Oct-19 14:26:41 GMT; path=/; domain=.typicode.com; HttpOnly
    x-powered-by: Express
    vary: Origin, Accept-Encoding
    access-control-allow-credentials: true
    expires: Sun, 21 Oct 2018 18:26:41 GMT
    x-content-type-options: nosniff
    etag: W/"105970-HCYFejK2YCxztz8++2rHnutkPOQ"
    via: 1.1 vegur
    cf-cache-status: REVALIDATED
    expect-ct: max-age=604800, report-uri="https://report-uri.cloudflare.com/cdn-cgi/beacon/expect-ct"
    server: cloudflare
    cf-ray: 46d466910cab3d77-MXP
    Cache-Control: public, max-age=60

推荐答案

十月. 2018(Retrofit 2.4或OKHTTP 3.11)完整解决方案

好,所以在线&使用OKHTTP或Retrofit进行脱机缓存已导致许多人在stackoverflow和其他论坛上遇到很多问题.整个互联网上都有大量误导性信息和无效代码示例.

Oct. 2018 (Retrofit 2.4 or OKHTTP 3.11) Complete Solution

Ok, so Online & Offline caching using OKHTTP or Retrofit has been causing so many problems for many people on stackoverflow and other forums. There are tons of misleading information and non-working code samples all over the internet.

因此,今天我将说明如何实现在线&使用Retrofit&的离线缓存OKHTTP,提供清晰的步骤+如何测试并知道您是从缓存还是从网络获取数据.

So, today I will explain how you can implement online & offline caching using Retrofit & OKHTTP with clear steps + How to test and know whether you are getting the data from cache or network.

如果获得504 Unsatisfiable Request (only-if-cached)Unable to resolve host "HOST": No address associated with hostname,则可以使用以下任何一种解决方案.

If you are getting a 504 Unsatisfiable Request (only-if-cached) OR an Unable to resolve host "HOST": No address associated with hostnamethen you can use any of the following solutions.

开始之前,您必须始终记住:

  • 确保您使用的是GET请求而不是POST!
  • 始终确保添加.removeHeader("Pragma"),如下所示(这使您可以覆盖服务器的缓存协议)
  • 在测试过程中避免使用HttpLoggingInterceptor,这可能在开始时引起一些混乱.最后,如果需要,可以启用它.
  • 如果您想使用Interceptor进行探索,则始终会从设备中删除您的应用程序,并在每次更改代码后再次重新安装它.否则,当旧的缓存数据仍在设备上时更改代码将导致您产生许多困惑和误导性推论!
  • 将拦截器添加到OKHTTPClient对象的顺序很重要!
  • Make sure you are using a GET request and not a POST!
  • Always make sure you add .removeHeader("Pragma") as shown below (This lets you override the server's caching protocol)
  • Avoid using the HttpLoggingInterceptor while testing, it can cause some confusion in the beginning. Enable it in the end if you want.
  • ALWAYS ALWAYS ALWAYS delete your app from the device and reinstall it again upon every change in code, if you want to explore using Interceptors. Otherwise changing code while the old cache data is still on the device will cause you lots of confusion and misleading deductions!
  • The order of adding Interceptors to OKHTTPClient object matters!

N.B:如果要依靠服务器的缓存协议进行联机和脱机缓存,那么请不要阅读这两种解决方案.只需阅读文章.您所需要做的就是创建一个缓存对象并将其附加到OKHTTPClient对象.

N.B: If you want to depend on your server's caching protocol for online and offline caching, then don't read the 2 solutions. Just read this article. All you need is to create a cache object and attache it to OKHTTPClient object.

解决方案1:(更长,但您拥有完全控制权)

Solution 1: (Longer, but you have full control)

  • 步骤1 :(创建onlineInterceptor)

  • Step 1: (Create onlineInterceptor)

   static Interceptor onlineInterceptor = new Interceptor() {
    @Override
    public okhttp3.Response intercept(Chain chain) throws IOException {
        okhttp3.Response response = chain.proceed(chain.request());
        int maxAge = 60; // read from cache for 60 seconds even if there is internet connection
        return response.newBuilder()
                .header("Cache-Control", "public, max-age=" + maxAge)
                .removeHeader("Pragma")
                .build();
    }
};

  • 步骤2 :(创建脱机拦截器)(仅当您要在脱机时缓存访问权限时)

  • Step 2: (Create Offline Interceptor) (Only if you want cache access when offline)

       static Interceptor offlineInterceptor= new Interceptor() {
       @Override
        public okhttp3.Response intercept(Chain chain) throws IOException {
        Request request = chain.request();
        if (!isInternetAvailable()) {
            int maxStale = 60 * 60 * 24 * 30; // Offline cache available for 30 days 
            request = request.newBuilder()
                    .header("Cache-Control", "public, only-if-cached, max-stale=" + maxStale)
                    .removeHeader("Pragma")
                    .build();
          }
          return chain.proceed(request);
       }
     };
    

  • 步骤3 :(创建缓存对象)

  • Step 3: (Create a cache object)

    int cacheSize = 10 * 1024 * 1024; // 10 MB
    Cache cache = new Cache(context.getCacheDir(), cacheSize);
    

  • 步骤4 :(将拦截器和缓存添加到OKHTTPClient对象)

  • Step 4: (Add interceptors and cache to an OKHTTPClient object)

        OkHttpClient okHttpClient = new OkHttpClient.Builder()
     // .addInterceptor(provideHttpLoggingInterceptor()) // For HTTP request & Response data logging
        .addInterceptor(OFFLINE_INTERCEPTOR)
        .addNetworkInterceptor(ONLINE_INTERCEPTOR)
        .cache(cache)
        .build();
    

  • 步骤5 :(如果使用的是Retrofit,请向其中添加OKHTTPClient对象)

  • Step 5:(If you are using Retrofit, add the OKHTTPClient object to it)

             retrofit = new retrofit2.Retrofit.Builder()
            .baseUrl(BASE_URL)
            .addConverterFactory(GsonConverterFactory.create())
            .client(okHttpClient)
            .build();
    

  • 完成!

    解决方案2:(只需使用一个库即可为您完成所有工作!但是要克服局限性)

    Solution 2: (Just use a library to do all that for you! But deal with the limitations)

    使用 OkCacheControl

    • 第1步(如上所示创建Cache对象)
    • 第2步(创建OKHTTPClient对象)

    • Step 1 (Create Cache object as shown above)
    • Step 2 (Create an OKHTTPClient object)

         OkHttpClient okHttpClient = OkCacheControl.on(new OkHttpClient.Builder())
         .overrideServerCachePolicy(1, MINUTES)
         .forceCacheWhenOffline(networkMonitor)
         .apply() // return to the OkHttpClient.Builder instance
       //.addInterceptor(provideHttpLoggingInterceptor())
         .cache(cache)
         .build();
    

  • 步骤3 :(如上所述,将OKHTTPClient对象附加到Retrofit)

  • Step 3:(Attach the OKHTTPClient object to Retrofit as shown above)

    步骤4 :(创建一个NetworkMonitor对象)

    Step 4: (Create a NetworkMonitor Object)

       static OkCacheControl.NetworkMonitor networkMonitor=new 
       OkCacheControl.NetworkMonitor() {
       @Override
        public boolean isOnline() {
        return isInternetAvailable();
       }
      };
    

  • 完成!

    测试: 为了知道您的设备是从网络还是从缓存中获取数据,只需将以下代码添加到Retrofit的onResponse方法中即可.

    Testing: In order to know whether your device is getting data from the network or from cache, simply add the following code to your onResponse method of Retrofit.

     public void onResponse(Call<List<RetroPhoto>> call, Response<List<RetroPhoto>> response) {
                if (response.raw().cacheResponse() != null) {
                    Log.e("Network", "response came from cache");
                }
    
                if (response.raw().networkResponse() != null) {
                    Log.e("Network", "response came from server");
                }
            }
    

    如果设备正在使用网络,您将收到来自服务器的响应".

    If the device is using the Network, you will get "response came from server".

    如果设备正在使用缓存,则您将获得上述两个响应!有关此的更多信息,请阅读文章.

    If device is using Cache, you will get both of the above responses! For more info about this read this article.

    有关使用OKHTTP拦截器的详细信息,请访问此页面.

    For more info about using OKHTTP interceptors go to this page.

    这篇关于改造OKHTTP脱机缓存不起作用的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

    查看全文
    登录 关闭
    扫码关注1秒登录
    发送“验证码”获取 | 15天全站免登陆