简体   繁体   English

OKHTTP3离线缓存

[英]OKHTTP3 Offline cache

I want to implement cache even if there is no internet connection(Offline) but still had no success, already look many example but still no luck 即使没有互联网连接(离线),我也想实现缓存,但是仍然没有成功,已经看起来很多示例,但是仍然没有运气

//FeedInterceptor Class 
public static Interceptor getOfflineInterceptor(final Context context){
    Interceptor interceptor = new Interceptor() {
        @Override
        public okhttp3.Response intercept(Chain chain) throws IOException {
            Request request = chain.request();
            if (!isNetworkAvailable(context)) {
                request = request.newBuilder()
                        .removeHeader("Pragma")
                        .header("Cache-Control", "public, only-if-cached")
                        .build();
            }
            return chain.proceed(request);
        }
    };

    return interceptor;
}


//OnCreate Activity
client = new OkHttpClient.Builder()
            .addNetworkInterceptor(FeedInterceptor.getOnlineInterceptor(this))
            .addInterceptor(FeedInterceptor.getOfflineInterceptor(this))
            .cache(cache)
            .build();

//After build Request
Response response = client.newCall(request).execute();
return response.body().string();

if offline the return comes as empty string. 如果离线,则返回为空字符串。 Is there something I miss or wrong? 有什么我想念或做错的吗?

In order to be able to reuse a cached response, it is necessary that the response itself declares itself to be "cacheable", by providing some headers (eg, Cache-Control: public or Cache-Control: max-age=3600 ). 为了能够重用缓存的响应,必须通过提供一些标头(例如, Cache-Control: publicCache-Control: max-age=3600 ),使响应本身声明自己为“可缓存”。 Did you check if your response contains such headers? 您是否检查过您的回复中是否包含此类标题?

Also, consider using the built-in constant CacheControl.FORCE_CACHE as a value for your cacheControl setter . 另外,请考虑使用内置常量CacheControl.FORCE_CACHE作为您的cacheControl setter的值。

Finally, be aware that (quoting from OkHttp documentation ): 最后,请注意(引用OkHttp文档 ):

Be warned: if you use FORCE_CACHE and the response requires the network, OkHttp will return a 504 Unsatisfiable Request response 警告:如果使用FORCE_CACHE ,并且响应需要网络,则OkHttp将返回504 Unsatisfiable Request响应

EDIT: 编辑:

Here's a full example. 这是一个完整的例子。

final CacheControl cacheControl = new CacheControl.Builder()
        .maxAge(60, TimeUnit.MINUTES)
        .build();

// Interceptor to ask for cached only responses
Interceptor cacheResponseInterceptor = chain -> {
    Response response = chain.proceed(chain.request());
    return response.newBuilder()
            .header("Cache-Control", cacheControl.toString())
            .build();
};

// Interceptor to cache responses
Interceptor cacheRequestInterceptor = chain -> {
    Request request = chain.request();
    request = request.newBuilder()
            .cacheControl(CacheControl.FORCE_CACHE)
            .build();

    return chain.proceed(request);
};

// Create a directory to cache responses. Max size = 10 MiB
Cache cache = new Cache(new File("okhttp.cache"), 10 * 1024 * 1024);

/*
 * Let's create the client. At the beginning the cache will be empty, so we will
 * add the interceptor for the request only after, for the 2nd call
 */
OkHttpClient client = new OkHttpClient.Builder()
        .cache(cache)
        .addNetworkInterceptor(cacheResponseInterceptor)
        .build();

// Let's do the call
Request request = new Request.Builder()
        .url("http://httpbin.org/get")
        .get()
        .build();
Response response = client.newCall(request).execute();
response.close();

// Let's add the interceptor for the request
client = client.newBuilder()
        .addInterceptor(cacheRequestInterceptor)
        .build();

// Let's do the same call
request = new Request.Builder()
        .url("http://httpbin.org/get")
        .get()
        .build();
response = client.newCall(request).execute();
response.close();

// Let's see if we had some issues with the cache
System.out.println("Is successful? " + response.isSuccessful());

Please note that since this is a "standalone" example, I had to do 2 calls: 请注意,由于这是一个“独立”示例,因此我必须进行2次调用:

  1. this call uses the network to get a valid response to cache, otherwise my cache would be empty. 此调用使用网络来获取对缓存的有效响应,否则我的缓存将为空。 In your case you don't need it, since normally you'd use the device data to do a "real" call; 在您的情况下,您不需要它,因为通常您会使用设备数据进行“真实”调用; Note that here I use the network interceptor, the one that adds the header saying "ok, you can cache this response". 请注意,这里我使用网络拦截器,该网络拦截器添加了标有“好的,您可以缓存此响应”的标头。
  2. I added the interceptor that forces to use the cache. 我添加了强制使用缓存的拦截器。 Here the network interceptor won't be used, since either the response is found in the cache, or a 504 response is returned. 这里不会使用网络拦截器,因为要么在缓存中找到响应,要么返回504响应。

Note also that you need to close the response , otherwise the cache won't be populated correctly. 另请注意, 您需要关闭响应 ,否则将无法正确填充缓存。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM