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

标签: 缓存 retrofit2 okhttp3-0 app
1695人阅读 评论(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

查看评论

手动缓存Retrofit+OkHttp响应体,不再局限于Get请求缓存

OkHttp的缓存问题,主要是通过http协议里面的control-cache控制缓存,而且是仅仅只能是Get请求才能缓存,如果Post请求OkHttp会让response返回null,同时报504错...
  • Iamzgx
  • Iamzgx
  • 2016-06-27 00:22:18
  • 7338

Android 使用RxJava+Retrofit +Realm 组合加载数据 <读取缓存 显示 请求网络数据 缓存最新数据 更新界面>(一)

Android 使用RxJava+Retrofit 组合加载数据 (一)
  • arieshao
  • arieshao
  • 2016-07-15 14:31:03
  • 2781

Retrofit2.0和Okhttp进行的缓存

原文:http://blog.csdn.net/picasso_l/article/details/50579884 简介 retrofit本身并没有缓存。 如果想缓存,它要么必须让retrofit...
  • qq_15807167
  • qq_15807167
  • 2016-08-17 12:00:19
  • 622

【Android】Retrofit框架缓存处理(离线缓存等)

1.简述上一篇介绍了Retrofit的基本使用,如果您还不了解请先查看Retrofit使用详解–有些相见恨晚 这篇文章;我们在开发app的时候,有一种情况不得不处理,就是在用户断网的清空下的一些页面显...
  • wangkeke1860
  • wangkeke1860
  • 2016-08-01 15:42:19
  • 4908

Android网络缓存,retrofit+okhttp

缓存策略和机制 http缓存 CacheControl类 拦截器
  • phomel
  • phomel
  • 2016-12-30 11:23:30
  • 1075

Retrofit2实现缓存。离线缓存、在线缓存及@headers控制缓存时间

参考来自 使用Retrofit和Okhttp实现网络缓存。 由于retrofit和okhttp都已经更新,在某些细节上参考的那篇博客已经不适用了,而且那篇博客并没有介绍@headers如何具体使用。这...
  • adzcsx2
  • adzcsx2
  • 2016-05-10 18:32:54
  • 3514

retrofit2.0缓存设置

前言 – 在 Android 开发过程中,Retrofit 的出现绝对是里程碑式的,说起 Retrofit 不得不说 square,这绝对是家l好公司,业界良心。 回到今天的主题...
  • changsimeng
  • changsimeng
  • 2017-01-22 15:38:18
  • 3115

Retrofit2.0+okhttp3实现缓存

参考文章:Retrofit2.0+okhttp3缓存机制以及遇到的问题 参考文章 : 使用Retrofit和Okhttp实现网络缓存。无网读缓存,有网根据过期时间重新请求 参考文章 : o...
  • u014316462
  • u014316462
  • 2016-09-19 17:54:18
  • 3746

retrofit2.0增加先读缓存后请求网络的功能

由于前段时间升级了retrofit版本到了2.1,导致原来写的缓存框架出现了点问题,后来在github上看到一个smartCache缓存框架 而其版本是2.0beta版和正式版有点差距,于是就自己更改...
  • lizubing1992
  • lizubing1992
  • 2016-08-05 15:49:21
  • 2652

Retrofit2.0单文件多文件上传(客户+端服务端)

  • 2016年09月09日 02:06
  • 26.68MB
  • 下载
    个人资料
    专栏达人 持之以恒
    等级:
    访问量: 30万+
    积分: 4198
    排名: 9100
    博客专栏
    最新评论