跳转至

缓存

缓存优势

  1. 页面秒开
  2. 减少服务器压力
  3. 无网络可用

Net缓存特点

  1. 缓存任何请求方式
  2. 缓存任何数据, File/图片/JSON/ProtoBuf等
  3. 限制最大缓存空间
  4. 使用DiskLruCache实现, 删除最近最少使用

配置缓存

不配置Cache是不会启用缓存的

NetConfig.initialize(Api.HOST, this) {
    // Net支持Http缓存协议和强制缓存模式
    // 当超过maxSize最大值会根据最近最少使用算法清除缓存来限制缓存大小
    cache(Cache(cacheDir, 1024 * 1024 * 128))
}

判断响应来自缓存

如果Response.cacheResponse不为null的时, 代表Response来自本地缓存

Http缓存协议

OkHttp默认的Http缓存协议控制, 要求以下条件

  • Get请求方式
  • 缓存使用Url为key, 因此Url改变会读不到缓存
  • 响应头控制缓存: Cache-Control


通过setCacheControl可以控制Http缓存协议, 原理是修改请求头

scopeNetLife {
    Post<String>(Api.PATH) {
        setCacheControl(CacheControl.FORCE_CACHE) // 强制使用缓存
        // setCacheControl(CacheControl.FORCE_NETWORK) // 强制使用网络
        // setCacheControl(CacheControl.Builder().noStore().noCache().build()) // 禁止缓存
    }.await()
}

如果无法实现Http标准缓存协议, 或要缓存Get以外的请求方法, 可以使用强制缓存模式

强制缓存模式

无论当前请求是否存在Http标准缓存协议, 当设置强制缓存模式时会无视Http缓存协议

scopeNetLife {
    tv.text =
        Post<String>(Api.PATH) {
            setCacheMode(CacheMode.REQUEST_THEN_READ) // 请求网络失败会读取缓存, 请断网测试
        }.await()
}
强制缓存模式 描述
READ 只读取缓存, 读不到NoCacheException
WRITE 只请求网络, 强制写入缓存
READ_THEN_REQUEST 先从缓存读取,如果失败再从网络读取, 强制写入缓存
REQUEST_THEN_READ 先从网络读取,如果失败再从缓存读取, 强制写入缓存

自定缓存Key

强制缓存模式有效, 缓存Key默认是请求方式+URL后产生的sha1值

如果要缓存区别请求参数, 请自定义缓存key

scopeNetLife {
    tv.text =
        Post<String>(Api.PATH) {
            setCacheMode(CacheMode.REQUEST_THEN_READ) // 请求网络失败会读取缓存, 请断网测试
            setCacheKey("请求热门信息" + params) // 具体值都行
        }.await()
}

缓存有效期

  1. 强制缓存模式有效, 标准Http缓存协议遵守协议本身的有效期
  2. 缓存有效期过期只是让缓存无效, 不会立即删除
    根据(最近最少使用)原则在缓存空间达到配置值时删除(即使缓存有效期未到)
scopeNetLife {
    tv.text =
        Post<String>(Api.PATH) {
            setCacheMode(CacheMode.REQUEST_THEN_READ) // 请求网络失败会读取缓存, 请断网测试
            setCacheValidTime(1, TimeUnit.DAYS) // 缓存仅一天内有效
        }.await()
}

预览(缓存+网络)

预览又可以理解为回退请求, 一般用于秒开首页或者回退加载数据

scopeNetLife {
    // 然后执行这里(网络请求)
    tv.text = Get<String>(Api.PATH) {
        setCacheMode(CacheMode.WRITE)
    }.await()
    Log.d("日志", "网络请求")
}.preview {
    // 先执行这里(仅读缓存), 任何异常都视为读取缓存失败
    tv.text = Get<String>(Api.PATH) {
        setCacheMode(CacheMode.READ)
    }.await()
    Log.d("日志", "读取缓存")
}

预览和加载两次有什么区别?

区别是preview可以控制以下行为

  1. breakError 读取缓存成功后不再处理请求的错误, 默认false
  2. breakLoading 读取缓存成功后立刻结束加载动画, 默认true