关闭

[置顶] Retrofit2.0+Okhttp不依赖服务端的数据缓存

标签: 缓存retrofit2okhttp3-0app
1613人阅读 评论(0) 收藏 举报
分类:

随着Retrofit在项目中的使用,替换的以前使用的网络框架,相关的缓存机制也要进行替换,网络上大部分的Retrofit+okhttp缓存资料都是进行针对所有url的而且需要服务端的配合。有些时候是先有服务然后app去调用这些服务,所以这个时候没有服务端的配合我们在前端实现缓存比较空难但并不是很可以。(举个列子,有一个原来的服务更本不支持cache,但是我们在app中需要缓存这个服务的数据,这应该是前一段时间替换网络库时最后遇到的问题)。

为什么要做缓存处理?

客观回答:

减少服务器负荷,降低延迟提升用户体验。复杂的缓存策略会根据用户当前的网络情况采取不同的缓存策略,比如在2g网络很差的情况下,提高缓存使用的时间;不用的应用、业务需求、接口所需要的缓存策略也会不一样,有的要保证数据的实时性,所以不能有缓存,有的你可以缓存5分钟,等等。

自己回答:

在绝大部分的项目中我们前端开发人员只是考虑用户的流量,用户在产品性能上的体验。所以有时候服务端和前端没有依赖,即服务不支持缓存那么前端又需要缓存那么我们应该怎么做?普通的缓存模式已经很难适应这种需求了,下面将的就是利用Retrofit2.0+OkHttp3.0的缓存原理去实现我们的需求。

Retrofit+OkHttp的缓存机制:

  • 在 data/data/<包名>/cache 下建立一个用来进行数据存储的文件夹,保持缓存数据。
  • 这样我们就可以在请求的时候,根据业务逻辑,请求网络数据或者读取缓存的数据。

缓存使用情况:

  • 一般情况下无网络,数据从缓存中读取;
  • 有网络则根据请求头,判断是请求网络还是读取缓存。

说到缓存,不是很了解的Http缓存的同学亦可以看一下浏览器 HTTP 协议缓存机制详解 这篇文章讲的很详细。

Cache控制:

该部分对理解怎么缓存很重要~!

1、用在request中的cache控制头

Pragma: no-cache :兼容早起HTTP协议版本 如1.0+
Cache-Control: no-cache ,表示不希望得到一个缓存内容。只是希望,cache设备可能忽略。
Cache-Control: no-store,表示client与server之间的设备不能缓存响应内容,并应该删除已有缓存。
Cache-Control: only-if-cached,表示只接受是被缓存的内容

2、用在response中控制cache的头

Cache-Control: max-age=3600,用相对于接收到的时间开始可缓存多久
Cache-Control: s-maxage=3600,与上面类似,只是s-maxage一般用在cache服务器上,并只对public缓存有效
Expires: Fri, 05 Jul 2002, 05:00:00 GMT基于GMT的时间,绝对时间,但该头容易受到本地错误时间影响
Cache-Control: must-revalidate 该头表示内容可以被缓存但每次必须询问是否有更新。

HTTP-请求、响应、缓存

代码实现:

看到这里应该对缓存有一定的了解了,那么现在来看看怎么利用Retrofit2.0+Okhttp缓存的实现。

创建缓存文件,并对okhttp进行设置

public class RetrofitApiFactory{
    private static OkHttpClient okHttpClient = null ;
    private static File cacheFile = new File(ImageUtils.getAppCacheDir(), "xxxCache");
    private static Cache cache = new Cache(cacheFile, 1024 * 1024 * 50);
    /******中间代码省略*****/
    public static void initOkHttpClient(){
        okHttpClient =
                new OkHttpClient.Builder()
                        .cache(cache)
                        .readTimeout(TIME_OUT, TimeUnit.SECONDS)
                        .writeTimeout(TIME_OUT, TimeUnit.SECONDS)
                        .addInterceptor(new JobInterceptor("Interceptor"))  
                        //only 有网情况下,一分钟内每次请求都会重新请求,不会走缓存
                        .addNetworkInterceptor(new JobInterceptor("NetworkInterceptor"))    
                        //only 如果超过1分钟,离线请求不成功
                        .build();
        clearCacheMap() ;
    }
}

控制Cache中最最最主要的部分:

public class JobInterceptor implements Interceptor {
    /******中间代码省略*****/
    @Override
    public Response intercept(Chain chain) throws IOException {
        Request request = chain.request() ;
        if (!TextUtils.isEmpty(getCookie())) {
            if (!NetworkDetection.getIsConnected()) {
                try {
                    request = request
                            .newBuilder()
                            .addHeader("Cookie", getCookie())
                            .cacheControl(CacheControl.FORCE_CACHE)
                            .build();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            } else {
                try {
                    request = request
                            .newBuilder()
                            .addHeader("Cookie", getCookie())
                            .build();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }
        Response response = null;
        try {
            response = chain.proceed(request);
            if(!response.isSuccessful()){
                RetrofitApiFactory.initOkHttpClient();
            } else {//如果请求体有缓存数据的需要那么对响应体进行缓存
                int maxAge = request.cacheControl().maxAgeSeconds();
                if (request.cacheControl().isPublic() && maxAge > 1) {
                    response = response.newBuilder()
                            .removeHeader("Pragma")//清楚响应体对Cache有影响的信息
                            .removeHeader("Cache-Control")//清楚响应体对Cache有影响的信息
                            .header("Cache-Control", "public, max-age=" + maxAge)
                            .build();
                }
            }
        } catch (IOException e) {
            RetrofitApiFactory.initOkHttpClient();
            throw new IOException(e) ;
        }

        return response;
    }
}

接口使用:

@Headers("Cache-Control: public, max-age=86400")
@GET
Call<ResponseBody> getCacheData(@Url String url);

解析:

上面的绝大部分内容大家都在类似的文章上看到的。这里主要讲一下几点:

一、我们所用的接口服务不支持缓存,所以我不能只修改头信息而让服务端返回的response响应体去实现数据本地缓存。当然在没有网络的情况下我们可以尝试去读取缓存。

二、因为服务端没有提供response响应体的缓存,所以我们清除response响应体的Pragma、Cache-Control信息,然后根据自己设定的request请求体中的Cache信息去修改response响应体的Cache信息从而达到数据可以缓存。

三、在开发的过程中遇到如果一个接口在某次请求返回404,那么以后的结果总是请求失败的404页面。所以在请求失败的时候需要初始化OkHttpClient实例。

如有问题,欢迎沟通指正~!~!
参考文章Retrofit-Cache

0
0
查看评论

基于Retrofit2,okhttp3的数据缓存(cache)技术

在有网的情况下设置缓存时间t(s),在有网或者无网时都在t(s)之后就会缓存数据清空; 有很多局限性;可以查看: [基于Retrofit2,okhttp3的数据缓存(cache)技术–深入挖掘]做了更深入、更全面的解决;](http://blog.csdn.net/yangjianbo456/a...
  • yangjianbo456
  • yangjianbo456
  • 2016-07-29 12:25
  • 1640

Retrofit 2.X使用详解之请求头

Retrofit提供了两个两种定义HTTP请求头字段的方法即静态和动态。静态头不能改变为不同的请求,头的键和值是固定的且不可改变的,随着程序的打开便已固定。在Retrofit 2.0中,OkHttp 是必须的,并且自动设置为了依赖。这样,我们又可以采用OkHttp添加请求头的方式添加请求头。动态添加...
  • IO_Field
  • IO_Field
  • 2016-08-20 19:54
  • 8768

retrofit2.0缓存设置

前言 – 在 Android 开发过程中,Retrofit 的出现绝对是里程碑式的,说起 Retrofit 不得不说 square,这绝对是家l好公司,业界良心。 回到今天的主题,OKHttp3 网络层 缓存实现与分析。有人可能会说,你这...
  • changsimeng
  • changsimeng
  • 2017-01-22 15:38
  • 2870

教你如何使用okhttp缓存

okhttp缓存使用,基于okhttp3.5.0
  • u014614038
  • u014614038
  • 2016-04-21 20:07
  • 18001

OKHTTP之缓存配置详解

前言在Android开发中我们经常要进行各种网络访问,比如查看各类新闻、查看各种图片。但有一种情形就是我们每次重复发送的网络请求其实返回的内容都是一样的。比如一个电影类APP,每一次向服务器申请某个电影的相关信息,如封面、简介、演员表等等,它们的信息都是一样的。显然,这样有点浪费资源,最主要的是这些...
  • briblue
  • briblue
  • 2016-10-25 11:47
  • 11300

okhttp的使用极其缓存

http://blog.csdn.net/u014614038/article/details/51210685 服务器支持和不支持 http://blog.csdn.net/copy_yuan/article/details/51524907 okhttp的使用 http://www.cnblo...
  • dygcomed
  • dygcomed
  • 2017-04-12 22:28
  • 495

Okhttp----缓存的加入方式----附完整demo

Okhttp是由Sqare公司开发的开源网络访问库,目前在Android和Java开发中有着广泛的应用。在Android开发中和Retrofit结合可以非常方便地调用网络接口。 使用缓存可以让我们的app不用长时间地显示令人厌烦的加载圈,提高了用户体验,而且还节省了流量,在数据更新不是很频繁的地方...
  • copy_yuan
  • copy_yuan
  • 2016-05-28 14:51
  • 12244

OKHTTP之缓存配置详解

前言 在Android开发中我们经常要进行各种网络访问,比如查看各类新闻、查看各种图片。但有一种情形就是我们每次重复发送的网络请求其实返回的内容都是一样的。比如一个电影类APP,每一次向服务器申请某个电影的相关信息,如封面、简介、演员表等等,它们的信息都是一样的。显然,这样有点浪费资源,最主要...
  • u012917700
  • u012917700
  • 2016-11-30 08:38
  • 970

Android okHttp 实战(四):okHttp网络请求之缓存控制Cache-Control

原文地址:http://www.cnblogs.com/whoislcj/p/5537640.html 前面的学习基本上已经可以完成开发需求了,但是在项目中有时会遇到对请求做个缓存,当没网络的时候优先加载本地缓存,基于这个需求我们来学习一直okHttp的Cache-Control。 ...
  • u014031072
  • u014031072
  • 2016-12-29 08:03
  • 1351

okhttp3 缓存如此简单

不需要添加addNetworkInterceptorOkHttpClient mOkHttpClient = new OkHttpClient.Builder()mOkHttpClient.addInterceptor(new BasicParamsInterceptor(mCacheTime))p...
  • TT5267621
  • TT5267621
  • 2016-11-17 12:27
  • 5540
    个人资料
    • 访问:288678次
    • 积分:3978
    • 等级:
    • 排名:第9390名
    • 原创:329篇
    • 转载:17篇
    • 译文:10篇
    • 评论:35条
    博客专栏
    最新评论