Android中okhttp3.4.1+retrofit2.1.0实现离线缓存

关于Retrofit+OkHttp的强大这里就不多说了,还没了解的同学可以自行去百度。这篇文章主要讲如何利用Retrofit+OkHttp来实现一个较为简单的缓存策略:
即有网环境下我们请求数据时,如果没有缓存或者缓存过期了,就去服务器拿数据,并且将新缓存保存下来,如果有缓存而且没有过期,则直接使用缓存。无网环境下我们请求数据时,缓存没过期则直接使用缓存,缓存过期了则无法使用,需要重新联网获取服务器数据。

缓存处理还是很有必要的,它有效的减少服务器负荷,降低延迟提升用户体验,同时也方便用户即使在没网络的情况下也能使用APP。

之前一直有一个疑惑,既然Retrofit已经是对OkHttp的一个封装了,为什么还一直说Retrofit+OkHttp要一起搭配使用,后来才知道其实OKHttp很重要的一个作用,就是对一些网络请求的配置,例如连接超时,读取超时,以及一些缓存配置等。

一、添加依赖

compile 'com.squareup.retrofit2:retrofit:2.1.0'
compile 'com.squareup.retrofit2:converter-gson:2.1.0'
compile 'com.squareup.okhttp3:okhttp:3.4.1'
compile 'com.squareup.okhttp3:logging-interceptor:3.4.1'

二、配置OkHttpClient(设置缓存路径和缓存文件大小)

File httpCacheDirectory = new File(Environment.getExternalStorageDirectory(), "HttpCache");//这里为了方便直接把文件放在了SD卡根目录的HttpCache中,一般放在context.getCacheDir()中 int cacheSize = 10 * 1024 * 1024;//设置缓存文件大小为10M Cache cache = new Cache(httpCacheDirectory, cacheSize); httpClient = new OkHttpClient.Builder() .connectTimeout(10, TimeUnit.SECONDS)//设置连接超时 .readTimeout(10, TimeUnit.SECONDS)//读取超时 .writeTimeout(10, TimeUnit.SECONDS)//写入超时 .addNetworkInterceptor(REWRITE_CACHE_CONTROL_INTERCEPTOR)//添加自定义缓存拦截器(后面讲解),注意这里需要使用.addNetworkInterceptor .cache(cache)//把缓存添加进来 .build();

三、配置Retrofit

retrofit = new Retrofit.Builder() .baseUrl(baseUrl) .client(httpClient)//把OkHttpClient添加进来 .addConverterFactory(GsonConverterFactory.create()) .build();

四、编写拦截器

  我们知道其实Retrofit+OkHttp的缓存主要通过拦截器实现,所以主要做的功夫也在拦截器里面。

static Interceptor REWRITE_CACHE_CONTROL_INTERCEPTOR = new Interceptor() { @Override public Response intercept(Chain chain) throws IOException { Request request = chain.request(); //网上很多示例代码都对在request请求前对其进行无网的判断,其实无需判断,无网自动访问缓存 // if(!NetworkUtil.getInstance().isConnected()){ // request = request.newBuilder() // .cacheControl(CacheControl.FORCE_CACHE)//只访问缓存 // .build(); // } Response response = chain.proceed(request); if (NetworkUtil.getInstance().isConnected()) { int maxAge = 60;//缓存失效时间,单位为秒 return response.newBuilder() .removeHeader("Pragma")//清除头信息,因为服务器如果不支持,会返回一些干扰信息,不清除下面无法生效 .header("Cache-Control", "public ,max-age=" + maxAge) .build(); } else { //这段代码设置无效 // int maxStale = 60 * 60 * 24 * 28; // 无网络时,设置超时为4周 // return response.newBuilder() // .header("Cache-Control", "public, only-if-cached, max-stale=" + maxStale) // .removeHeader("Pragma") // .build(); } return response; } };

到这里,其实已经可以实现了我们开头所说的缓存效果了。

  但是,上面设置的每个接口缓存时间都一样,例如我现在想让不同接口的缓存数据失效时间都不一样,甚至有些接口不缓存数据,应该怎么做呢?其实也很简单

首先我们只需要在接口前面添加@Headers参数(max-age代表缓存时间,单位为秒,示例中表示缓存失效时间为60s,想要多少时间可以自行设置),不设置@Headers参数则不进行缓存。

@Headers("Cache-Control:public ,max-age=60") @GET("getBusiness.action")//商店信息 Call<RestaurantInfoModel> getRestaurantInfo(@Query("userId") String userId,@Query("businessId") String businessId);

同时,我们的缓存拦截器也要做下简单的修改(去掉了之前的注释代码)

static Interceptor REWRITE_CACHE_CONTROL_INTERCEPTOR = new Interceptor() { @Override public Response intercept(Chain chain) throws IOException { Request request = chain.request(); Response response = chain.proceed(request); if (NetworkUtil.getInstance().isConnected()) { //获取头部信息 String cacheControl =request.cacheControl().toString(); return response.newBuilder() .removeHeader("Pragma")//清除头信息,因为服务器如果不支持,会返回一些干扰信息,不清除下面无法生效 .header("Cache-Control", cacheControl) .build(); } return response; } };

*注意:

1.只能缓存Get请求的接口,不能缓存Post请求的接口

2.OkHttpClient需要用.addNetworkInterceptor添加缓存拦截器,不能使用.addInterceptor,也无需两者同时使用。

3.此方法无需服务器端任何操作,适用于服务器端没有其他缓存策略,如果服务器端有自己的缓存策略代码应该做相应的修改,以适应服务器端。

附上所有代码:

/** * 简单封装的Retroit初始化类 */ public class initRetrofit { private static String baseUrl = "http://202.171.212.154:8080/hh/"; private static OkHttpClient httpClient; private static Retrofit retrofit; public static Retrofit initRetrofit() { //缓存路径和大小 File httpCacheDirectory = new File(Environment.getExternalStorageDirectory(), "HttpCache"); int cacheSize = 10 * 1024 * 1024; Cache cache = new Cache(httpCacheDirectory, cacheSize); //日志拦截器 HttpLoggingInterceptor interceptor = new HttpLoggingInterceptor(); interceptor.setLevel(HttpLoggingInterceptor.Level.BODY); httpClient = new OkHttpClient.Builder() .connectTimeout(10, TimeUnit.SECONDS)//设置连接超时 .readTimeout(10, TimeUnit.SECONDS)//读取超时 .writeTimeout(10, TimeUnit.SECONDS)//写入超时 .addInterceptor(interceptor)//添加日志拦截器 .addNetworkInterceptor(REWRITE_CACHE_CONTROL_INTERCEPTOR)//添加缓存拦截器 .cache(cache)//把缓存添加进来 .build(); retrofit = new Retrofit.Builder() .baseUrl(baseUrl) .client(httpClient) .addConverterFactory(GsonConverterFactory.create()) .build(); return retrofit; } public static RetrofitAPI getService() { return initRetrofit().create(RetrofitAPI.class); } // //缓存拦截器,不同接口不同缓存 // static Interceptor REWRITE_CACHE_CONTROL_INTERCEPTOR = new Interceptor() { // @Override // public Response intercept(Chain chain) throws IOException { // // Request request = chain.request(); // Response response = chain.proceed(request); // // if (NetworkUtil.getInstance().isConnected()) { // String cacheControl =request.cacheControl().toString(); // return response.newBuilder() // .removeHeader("Pragma")//清除头信息,因为服务器如果不支持,会返回一些干扰信息,不清除下面无法生效 // .header("Cache-Control", cacheControl) // .build(); // } // return response; // } // }; //缓存拦截器,统一缓存60s static Interceptor REWRITE_CACHE_CONTROL_INTERCEPTOR = new Interceptor() { @Override public Response intercept(Chain chain) throws IOException { Request request = chain.request(); Response response = chain.proceed(request); if (NetworkUtil.getInstance().isConnected()) { int maxAge = 60*60*24*2;//缓存失效时间,单位为秒 return response.newBuilder() .removeHeader("Pragma")//清除头信息,因为服务器如果不支持,会返回一些干扰信息,不清除下面无法生效 .header("Cache-Control", "public ,max-age=" + maxAge) .build(); } return response; } }; }

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持脚本之家。

时间: 2024-10-27 06:28:06

Android中okhttp3.4.1+retrofit2.1.0实现离线缓存的相关文章

Android中okhttp3.4.1+retrofit2.1.0实现离线缓存_Android

关于Retrofit+OkHttp的强大这里就不多说了,还没了解的同学可以自行去百度.这篇文章主要讲如何利用Retrofit+OkHttp来实现一个较为简单的缓存策略: 即有网环境下我们请求数据时,如果没有缓存或者缓存过期了,就去服务器拿数据,并且将新缓存保存下来,如果有缓存而且没有过期,则直接使用缓存.无网环境下我们请求数据时,缓存没过期则直接使用缓存,缓存过期了则无法使用,需要重新联网获取服务器数据. 缓存处理还是很有必要的,它有效的减少服务器负荷,降低延迟提升用户体验,同时也方便用户即使在

Android 中Volley二次封装并实现网络请求缓存

Android 中Volley二次封装并实现网络请求缓存 Android目前很多同学使用Volley请求网络数据,但是Volley没有对请求过得数据进行缓存,因此需要我们自己手动缓存. 一下就是我的一种思路,仅供参考 具体使用方法为: HashMap<String,String> params = new HashMap<>(); params.put("id", "1"); params.put("user", &quo

Android中okhttp3使用详解

一.引入包 在项目module下的build.gradle添加okhttp3依赖 compile 'com.squareup.okhttp3:okhttp:3.3.1' 二.基本使用 1.okhttp3 Get 方法 1.1 .okhttp3 同步 Get方法 /** * 同步Get方法 */ private void okHttp_synchronousGet() { new Thread(new Runnable() { @Override public void run() { try {

详解Android中OkHttp3的例子和在子线程更新UI线程的方法

okHttp用于android的http请求.据说很厉害,我们来一起尝尝鲜.但是使用okHttp也会有一些小坑,后面会讲到如何掉进坑里并爬出来. 首先需要了解一点,这里说的UI线程和主线程是一回事儿.就是唯一可以更新UI的线程.这个只是点会在给okHttp填坑的时候用到.而且,这个内容本身在日常的开发中也经常用到,值得好好学一学. okHttp发起同步请求 第一个列子是一个同步请求的例子. private void performSyncHttpRequest() { OkHttpClient

Android中Retrofit 2.0直接使用JSON进行数据交互

之前使用Retrofit都是将JSON串转化为POJO对象,针对不同的业务协议,定义相应的接口和参数列表.但是此种方式一般用在自己内部协议基础上,具体大的项目中,有些第三方的集成功能,一般都采用统一的方式即请求JSON和回应JSON进行数据交互,不可能每个第三方协议都会去定义与协议相应的POJO对象. HTTP肯定有GET和POST方法,先定义Retrofit Api的interface: package com.hdnetworklib.network.http; import java.ut

Android中EditText光标在4.0中的bug及解决方法_Android

本文分析了Android中EditText光标在4.0中的bug及解决方法.分享给大家供大家参考,具体如下: 一.问题: 不知道为什么,我的EditText的在我自己的手机中出现的时候,他的光标就变得没有了,我开始还以为是光标不见了,后面我修改了一下EditText的背景颜色,才发现是因为光标的颜色变成了白色,所以没有看见. 二.解决办法 : 复制代码 代码如下: android:textCursorDrawable 设置值为"@null",但是我觉得那个不怎么好看,那个地方也可以替换

Android 中的蓝牙开发库 - 休息10分钟:听说蓝牙4.0马上要火啦?!

Android 中的蓝牙开发库 - 听说蓝牙4.0马上要火啦?! 太阳火神的美丽人生 (http://blog.csdn.net/opengl_es) 本文遵循"署名-非商业用途-保持一致"创作公用协议 转载请保留此句:太阳火神的美丽人生 -  本博客专注于 敏捷开发及移动和物联设备研究:iOS.Android.Html5.Arduino.pcDuino,否则,出自本博客的文章拒绝转载或再转载,谢谢合作. package android.bluetooth 提供管理蓝牙功能的类,诸如扫

Android中EditText光标在4.0中的bug及解决方法

本文分析了Android中EditText光标在4.0中的bug及解决方法.分享给大家供大家参考,具体如下: 一.问题: 不知道为什么,我的EditText的在我自己的手机中出现的时候,他的光标就变得没有了,我开始还以为是光标不见了,后面我修改了一下EditText的背景颜色,才发现是因为光标的颜色变成了白色,所以没有看见. 二.解决办法 : 复制代码 代码如下:android:textCursorDrawable 设置值为"@null",但是我觉得那个不怎么好看,那个地方也可以替换成

Android中使用开源框架eventbus3.0实现fragment之间的通信交互

1.概述 在之前的博文中简单介绍过如何实现fragment之间的信息交互:<Android中Fragment与Activity之间的交互(两种实现方式)>,今天继续给大家介绍一种可以实现此效果的另外一种方式EventBus.(相比于handler,接口回调,bundle传参,这个简单好用到哭) EventBus是Android下高效的发布/订阅事件的消息总线.作用是可以代替传统的Intent,Handler,Broadcast或接口函数在Fragment.Activity.Service.线程