这篇博客主要和大家说说okhttp的缓存。之前踩了好多坑,反正看了很多帖子做了很多试验,发现网上的很多都不怎么么正确,我的疑问也一直没有解决。今天这个这个是真实的自己写的接口实现过的。是真的正确的也解决了我们需要的2种缓存的需求
我先说说我们为啥要缓存。1.处理高并发的问题:当我们的用户量比较大的时候我们的服务器 有时候可能受不了所以我们要把那些并不是经常更新和不是很重要的信息缓存下来。我们只需要去请求那些主要的信息。还有就是有时候我们很无聊就是在app界面刷新刷新刷新,这样的话我们就可以不用把这个看成有效的请求。这时候我们就可以将缓存到本地的数据展示出来,这样的话我们就不用给服务器压力了。
2。这个就是我么没有网络的情况下要显示的缓存。我们有的需求就是我们没有网络的时候我们要展示我们上次显示的信息。这样的话我么就要用到我们的缓存了。
这里就说到了我们的两种缓存:
一、无论有无网络我们都去获取缓存的数据(我们会设置一个缓存时间,在某一段时间内(例如60S)去获取缓存数据。超过60S我们就去网络重新请求数据)
二、有网络的时候我们就去直接获取网络上面的数据。当没有网络的时候我们就去缓存获取数据。
现在说一下基本的知识把,为我们的后面讲的2种缓存打下最简单的基础。如果了解Retrofit,okhtt的朋友可以忽略这里的信息。
一、环境的搭建和集成
1.先集成okhttp和retrofit我就直接贴出来我的项目里面的了。
compile 'com.squareup.okhttp3:okhttp:3.4.1' compile 'com.squareup.retrofit2:retrofit:2.1.0' compile 'com.squareup.okio:okio:1.6.0' compile 'com.google.code.gson:gson:2.7' compile 'com.squareup.retrofit2:converter-gson:2.0.2'这样配置就可以了。
2.最简单的使用我就不说了。直接调用了。
OkHttpClient.Builder builder = new OkHttpClient.Builder();
OkHttpClient client = new OkHttpClient.Builder()
.retryOnConnectionFailure(true)//连接失败后是否重新连接
.connectTimeout(15, TimeUnit.SECONDS)//超时时间15S
.build();
Retrofit retrofit = new Retrofit
.Builder()
.baseUrl(AppConstants.RequestPath.HOST)
.client(client)//设置okhttp
.addConverterFactory(GsonConverterFactory.create(new Gson()))//解析数据
.build();
server = retrofit.create(ApiServer.class);
那么这里就是我们最简单的调用了有了server就很简单了啦。直接调用Api里面的自己编写的接口。
对于okhtt+retrofit不会使用的大家可以去看看帖子啊。这里就过多讲了啊。主要讲缓存策略的问题。
说说缓存吧。
在trofit自己是不支持缓存的。要做缓存用的是okhttp的功能,主要利用的是拦截器。这里一定要看清楚okhtt添加拦截器有两种。看清楚啊,很多时候这样的小的设置可能然我们浪费一天的时间的。有1.addInterceptor ,和2.addNetworkInterceptor这两种。他们的区别简单的说下,不知道也没关系,addNetworkInterceptor添加的是网络拦截器,他会在在request和resposne是分别被调用一次,addinterceptor添加的是aplication拦截器,他只会在response被调用一次。这个如果不知道也没有太多关系,不影响我们的这次操作,如果真的想要知道这些的话就去网上找找这个相关的一些东西看看,个人感觉还是比较重要的,但是如果这里过多的将的话感觉没有什么意义。
一、无论有无网络我们都先获取缓存的数据。
1.先要创建拦截器。
/**
* 一、无论有无网路都添加缓存。
* 目前的情况是我们这个要addNetworkInterceptor
* 这样才有效。经过本人测试(chan)测试有效.
* 60S后如果没有网络将获取不到数据,显示连接失败
*/
static Interceptor netInterceptor = new Interceptor() {
@Override
public Response intercept(Chain chain) throws IOException {
Request request = chain.request();
Response response = chain.proceed(request);
/*String cacheControl = request.header("Cache-Control");
if (TextUtils.isEmpty(cacheControl)) {
cacheControl = "public, max-age=60";
}*/
int maxAge = 60;
return response.newBuilder()
.removeHeader("Pragma")// 清除头信息,因为服务器如果不支持,会返回一些干扰信息,不清除下面无法生效
.removeHeader("Cache-Control")
.header("Cache-Control", "public, max-age=" + maxAge)
.build();
}
};
2.这样的话就写好了拦截器,然后哦就是把拦截器设置到okhttp里面
File cacheFile = new File(BaseApp.getInstance().getCacheDir(), "caheData");
//设置缓存大小
Cache cache = new Cache(cacheFile, DEFAULT_DIR_CACHE);//google建议放到这里
OkHttpClient client = new OkHttpClient.Builder()
.retryOnConnectionFailure(true)//连接失败后是否重新连接
.connectTimeout(15, TimeUnit.SECONDS)//超时时间15S
.addNetworkInterceptor(cacheInterceptor)//这里大家一定要注意了是addNetworkOnterceptor别搞错了啊。
.cache(cache)
.build();
我的操作了4次服务器之打印了一次也就是我们在60S只能无论我怎么点击只访问了一次数据。第一次是有网络的时候我获取了数据缓存了。第二次也是有网络的时候我获取的还是缓存的数据。第三次是我段网络后的数据还是有获取的缓存。第四次是我没有网络了,但是超过了设置的60S所以显示连接服务器失败。这样良心的截图说明我想够了吧。还有一点就算是有网络超过了60S我们获取的数据不就是缓存里面的数据了。第一种缓存比较简单也很好配置。
二、有网络的时候我们获取网络的数据或者自己设置一定的缓存,没有网络的时候我们获取缓存的数据。
1.所有的配置基本上一致,唯一不同的就是我们的拦截器的设置,那么我们的这种缓存的拦截器该怎么写呢。下面贴出来代码。大家要是有不懂的可以留言我可以一句句给大家解答,我也写了点注释在上面
public class CacheInterceptor implements Interceptor {
@Override
public Response intercept(Chain chain) throws IOException {
Request request = chain.request();//获取请求
//这里就是说判读我们的网络条件,要是有网络的话我么就直接获取网络上面的数据,要是没有网络的话我么就去缓存里面取数据
if(!NetworkUtils.isNetworkAvailable(BaseApp.getInstance().getApplicationContext())){
request = request.newBuilder()
//这个的话内容有点多啊,大家记住这么写就是只从缓存取,想要了解这个东西我等下在
// 给大家写连接吧。大家可以去看下,获取大家去找拦截器资料的时候就可以看到这个方面的东西反正也就是缓存策略。
.cacheControl(CacheControl.FORCE_CACHE)
.build();
Log.d("CacheInterceptor","no network");
}
Response originalResponse = chain.proceed(request);
if(NetworkUtils.isNetworkAvailable(BaseApp.getInstance().getApplicationContext())){
//这里大家看点开源码看看.header .removeHeader做了什么操作很简答,就是的加字段和减字段的。
String cacheControl = request.cacheControl().toString();
return originalResponse.newBuilder()
//这里设置的为0就是说不进行缓存,我们也可以设置缓存时间
.header("Cache-Control", "public, max-age=" + 0)
.removeHeader("Pragma")
.build();
}else{
int maxTime = 4*24*60*60;
return originalResponse.newBuilder()
//这里的设置的是我们的没有网络的缓存时间,想设置多少就是多少。
.header("Cache-Control", "public, only-if-cached, max-stale="+maxTime)
.removeHeader("Pragma")
.build();
}
}
}
2.设置Interceptor
这个大家注意了和之前设置的不同。也就一点点不同而已。我给出我的良心代码吧,等下还有良心截图。
OkHttpClient.Builder builder = new OkHttpClient.Builder(); //设置缓存路径 File cacheFile = new File(BaseApp.getInstance().getCacheDir(), "caheData"); //设置缓存大小 Cache cache = new Cache(cacheFile, DEFAULT_DIR_CACHE); OkHttpClient client = new OkHttpClient.Builder() .retryOnConnectionFailure(true)//连接失败后是否重新连接 .connectTimeout(15, TimeUnit.SECONDS)//超时时间15S .addInterceptor(new CacheInterceptor())//也就这里不同 .addNetworkInterceptor(new CacheInterceptor())//也就这里不同 .cache(cache) .build(); Retrofit retrofit = new Retrofit .Builder() .baseUrl(AppConstants.RequestPath.HOST)//baseURL提倡以“/”结尾 .client(client)//设置okhttp .addConverterFactory(GsonConverterFactory.create(new Gson()))//解析数据 .build(); server = retrofit.create(ApiServer.class);大家看看也就是添加拦截器的一点点地方不同。我良心截图了。
我第一次操作是有网络的时候很明显是最新数据,第二次也是有网络的时候我没有设置缓存数据,这样的话我服务器又收到了相应,后面几次都是没有网络的时候我的数据就是获取的缓存的数据。
总结:好了良心之作写完了。缓存的原理啥的网上一大堆我就不在这里讲了。有不知道的地方大家可以顺藤摸瓜一步步找出来然后学习
http://www.oschina.net/news/41397/web-cache-knowledge 这个是缓存的。1.缓存原理2.拦截器3retrofit+okhttp+Rxjava这样的教学一大堆。大家可以去看看。