当前位置: 移动技术网 > IT编程>移动开发>Android > Android中okhttp3.4.1+retrofit2.1.0实现离线缓存

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

2019年07月24日  | 移动技术网IT编程  | 我要评论

紫菜包饭的做法,明天阅兵,旭晶流行歌曲网

关于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;
  }
 };
}

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

如对本文有疑问,请在下面进行留言讨论,广大热心网友会与你互动!! 点击进行留言回复

相关文章:

验证码:
移动技术网