OkHttp 缓存实战

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了OkHttp 缓存实战相关的知识,希望对你有一定的参考价值。

参考技术A 在实际业务中可能某些查询数据,不经常变化,为了节省流量、提高响应速度和增强用户体验等,把变化频率小的数据缓存到本地,以实现复用。

OkHttp 的缓存功能使用起来也比较简单和灵活,接下来我们就来看看

配置缓存首先需要创建一个 Cache 对象,并且指定缓存目录和缓存大小,然后,调用用 OkHttpClient.Builder() 的 cache() 方法来配置创建的缓存对象。如下所示:

如果在服务端的接口响应中包含了合适 Cache-Control 响应头,那么, OkHttp 就会默认按此响应头,对数据进行缓存。

Cache-Control 响应头是缓存的一个重点,如果包含了此响应头,在网络请求时,会首先判断缓存是否有效,若有效则直接读取缓存数据,如果失效则会重新请求接口数据。

有些服务端接口,比如老接口或第三方接口,在响应头中不包含 Cache-Control ,或者缓存已被禁用。这种情况下要想让缓存功能正常工作,就需要使用自定义拦截器,通过拦截器在给请求的响应中添加合适的 Cache-Control 响应头即可。如下所示:

以上情况,无论是服务端响应包含 Cache-Control 头信息,还是通过拦截器设置的此头信息都属于全局配置,即所有的请求都会缓存,且缓存的时间相同。在实际业务中,可能是有些接口不需要缓存,或者不同接口要求缓存的时间要求不同。要解决这个问题有如下两种办法:

OkHttp 提供了如下两种默认的缓存控制器:

除了上面提供的默认缓存控制器外,还可以通过 CacheControl.Builder() 构建自定义的缓存控制器,可选的设置方法如下:

构建一个自定义缓存器如下所示:

当通过 CacheControl 类设置的缓存时间大于 Cache-Control 响应头时间时,缓存的有效时间为 Cache-Control 响应头时间,否则使用 CacheControl 类设置的时间。

基于此,所以我们可以给有需要的接口请求通过 CacheControl 类设置缓存策略,然后在拦截器中判断请求是否包含 Cache-Control 请求头,如果有就把 Cache-Control 请求头添加到响应中去,这样问题就解决了,修改后的拦截器如下:

在 OkHttp 中也可以使用缓存来减少网络请求。在 OkHttp 可以通过响应头中的 Cache-Control 控制缓存的有效时间,在服务端无法提供 Cache-Control 响应头时,可以通过自定义拦截器,在拦截器中对请求响应添加 Cache-Control 响应头。因为在拦截器中添加的响应头对所有的请求都生效,并且缓存策略相同,如果想不同的请求缓存控制不同,可以通过在 构造 Request 对象时,设置 CacheControl 对象,构建个性化缓存控制策略。

使用 Volley 和 OkHttp 时如何配置 Http 缓存?

【中文标题】使用 Volley 和 OkHttp 时如何配置 Http 缓存?【英文标题】:How to configure the Http Cache when using Volley with OkHttp? 【发布时间】:2015-07-13 12:51:58 【问题描述】:

我想尝试 Volley 与 OkHttp 的结合,但 Volley 缓存系统和 OkHttp 都依赖于 HTTP 规范中定义的 HTTP 缓存。那么如何禁用 OkHttp 的缓存来保留一份 HTTP 缓存呢?

编辑:我做了什么

public class VolleyUtil 
    // http://arnab.ch/blog/2013/08/asynchronous-http-requests-in-android-using-volley/
    private volatile static RequestQueue sRequestQueue;

    /** get the single instance of RequestQueue **/
    public static RequestQueue getQueue(Context context) 
        if (sRequestQueue == null) 
            synchronized (VolleyUtil.class) 
                if (sRequestQueue == null) 
                    OkHttpClient client = new OkHttpClient();
                    client.networkInterceptors().add(new StethoInterceptor());
                    client.setCache(null);
                    sRequestQueue = Volley.newRequestQueue(context.getApplicationContext(), new OkHttpStack(client));
                    VolleyLog.DEBUG = true;
                
            
        
        return sRequestQueue;
    

哪个OkHttpClient引用自https://gist.github.com/bryanstern/4e8f1cb5a8e14c202750

【问题讨论】:

你能告诉我们你做了什么 @Soham 感谢您的回复,我重新编辑了我的问题,谢谢。 【参考方案1】:

OkHttp 是一种类似于 HttpUrlConnection 的 HTTP 客户端,它实现了 HTTP 缓存,我们可以像下面这样禁用 OkHttp 的缓存:

OkHttpClient client = new OkHttpClient();
client.setCache(null);

然后,我们可以保留一份由 Volley 维护的 HTTP 缓存。

改进:

我想尝试回答索蒂的问题。

1 我想知道在使用 Volley 和 OkHttp 时,什么是好的缓存设置。

在我的项目中,我在所有 RESTful API 中使用一个 Volley requestQueue 实例,并且 OkHttp 作为 Volley 的传输层,如下所示。

public class VolleyUtil 
// http://arnab.ch/blog/2013/08/asynchronous-http-requests-in-android-using-volley/
private volatile static RequestQueue sRequestQueue;

/** get the single instance of RequestQueue **/
public static RequestQueue getQueue(Context context) 
    if (sRequestQueue == null) 
        synchronized (VolleyUtil.class) 
            if (sRequestQueue == null) 
                OkHttpClient client = new OkHttpClient();
                client.setCache(null);
                sRequestQueue = Volley.newRequestQueue(context.getApplicationContext(), new OkHttpStack(client));
                VolleyLog.DEBUG = true;
            
        
    
    return sRequestQueue;

2 我们应该依赖 Volley 还是 OkHttp 缓存?

是的,我将 Volley 缓存用于我的 HTTP 缓存而不是 OkHttp 缓存; 它对我很有用。

3 开箱即用的默认行为是什么?

对于排球:

它会自动为你创建一个“volley”默认缓存目录。

/** Default on-disk cache directory. */
private static final String DEFAULT_CACHE_DIR = "volley";


public static RequestQueue newRequestQueue(Context context, HttpStack stack, int maxDiskCacheBytes) 
    File cacheDir = new File(context.getCacheDir(), DEFAULT_CACHE_DIR);
    ……

对于 OkHttp:

我在源代码中找不到默认缓存,我们可以像这篇文章一样设置响应缓存 http://blog.denevell.org/android-okhttp-retrofit-using-cache.html

4.推荐的行为是什么以及如何实现?

正如this 帖子所说:

Volley 负责请求、加载、缓存、线程、同步等。它已准备好处理 JSON、图像、缓存、原始文本并允许进行一些自定义。

我更喜欢使用 Volley HTTP 缓存,因为它易于定制。

例如,我们可以像这样对缓存进行更多控制 Android Volley + JSONObjectRequest Caching.

【讨论】:

【参考方案2】:

OkHttp 忽略缓存的优雅方式是:

request.setCacheControl(CacheControl.FORCE_NETWORK);

【讨论】:

这仅适用于此处讨论的特定请求。 github.com/square/okhttp/issues/1496

以上是关于OkHttp 缓存实战的主要内容,如果未能解决你的问题,请参考以下文章

Android实战——okhttp3的使用和封装

CK2031-基于okhttp 3 的 Android 网络层架构设计实战

OKHttp实战篇(内部附赠真实案例+源码大公开)

实战:5分钟搞懂OkHttp断点上传

Android架构师之路 网络层架构设计与实战

Android架构师之路 网络层架构设计与实战