来北京一个多月了~
本周做组里技术分享时,被提问到一个问题:
Retrofit里自带网络线程调度(okHttp),适配RxJava后,内部是同步还是异步的?异步的话,就多了一层线程的包装了?
听完问题后,我的第一反应是,Jake大神怎么能没处理好这个问题呢,内部肯定是选择同步了吧,使用RxJava的理念就是线程调度都交给Rx好了。
但我确实没有看过这部分源码……当时只对动态代理感兴趣了……配合RxJava使用是随即开始了……
今天跑到公司,看了下源码,CallAdapter的处理,确实是同步的:)
真希望组里能用上Rx,太不喜欢现在的代码结构了。
还看到了这篇文章:
http://www.jianshu.com/p/07dac989272c
里面讲到了Volly对缓存提供了贴心的ttl和softTtl:
缓存处理;Volley自己就提供了一套完整的缓存处理方案,默认使用文件存储到磁盘中,并且提供了TTL
SOFTTTL这么体贴入微的机制;一个Request可能存在两个Response,对于需要显示缓存,再显示网络数据的场景真是爽的不要不要的。而Retrofit中并没有提供任何和缓存相关的方案
我都不好意思说自己曾经也看过Volly源码了,也用了Volly半年多……我确实没注意过
这个功能确实太好用了
只要没超期,那Volley去请求URL会先返回缓存的结果,再返回网络结果!
我记得okHttp对缓存处理是没有这样的过程的,它就是按照协议去做了。
现在的代码里都是自己存缓存。取数据时,自己先读缓存(也是文件形式),再读网络。
而Volly其实已经做好了。max-age设成极大值,就可以让缓存长时间有效了。
Volly貌似已经成为明日黄花了,但还是要再分析下源码,经典源码太多值得学的地方了。
Http协议里CacheControl有两个字段表达响应的过期时间:max-age和max-stale
前者表示:max-age秒内,网页再有请求,你不要来我服务端,直接取你本地缓存的结果好了
后者表示:max-stale秒内的请求,你可以使用本地缓存的,但还是要来我服务端问问,到底行不行,当然,这里要带上Last Modified等信息
如果服务端返回了304,那说明你本地缓存继续用吧,我不给你响应体
200的话,自然就带上了响应体。
先看CacheDispather.java, 注意里面的英文注释
if (!entry.refreshNeeded()) {
// Completely unexpired cache hit. Just deliver the response.
mDelivery.postResponse(request, response);
} else {
// Soft-expired cache hit. We can deliver the cached response,
// but we need to also send the request to the network for
// refreshing.
request.addMarker("cache-hit-refresh-needed");
request.setCacheEntry(entry);
// Mark the response as intermediate.
response.intermediate = true;
// Post the intermediate response back to the user and have
// the delivery then forward the request along to the network.
mDelivery.postResponse(request, response, new Runnable() {
@Override
public void run() {
try {
mNetworkQueue.put(request);
} catch (InterruptedException e) {
// Not much we can do about this.
}
}
});
}
}
再看一下cache.entry的构造,注意softExpire 和finalExpire
// Cache-Control takes precedence over an Expires header, even if both exist and Expires
// is more restrictive.
if (hasCacheControl) {
softExpire = now + maxAge * 1000;
finalExpire = mustRevalidate
? softExpire
: softExpire + staleWhileRevalidate * 1000;
} else if (serverDate > 0 && serverExpires >= serverDate) {
// Default semantic for Expire header in HTTP specification is softExpire.
softExpire = now + (serverExpires - serverDate);
finalExpire = softExpire;
}
codeKK上有对Volley源码分析
http://a.codekk.com/detail/Android/grumoon/Volley%20%E6%BA%90%E7%A0%81%E8%A7%A3%E6%9E%90
再补一张图(来源)
原作者写到试图让Retrofit支持这样的功能,但没有下文。
我试了下,首先拦截器没法实现这个功能,在ok对缓存里的处理里也不行,只能在回调结果处实现?
okHttp里AsyncCall里execute
@Override protected void execute() {
boolean signalledCallback = false;
try {
Response response = getResponseWithInterceptorChain(forWebSocket);
if (canceled) {
signalledCallback = true;
responseCallback.onFailure(originalRequest, new IOException("Canceled"));
} else {
signalledCallback = true;
responseCallback.onResponse(response);
}
} catch (IOException e) {
if (signalledCallback) {
// Do not signal the callback twice!
logger.log(Level.INFO, "Callback failure for " + toLoggableString(), e);
} else {
Request request = engine == null ? originalRequest : engine.getRequest();
responseCallback.onFailure(request, e);
}
} finally {
client.dispatcher().finished(this);
}
}
}
在这里先去缓存拿一个结果,回调下onResponse,再实际去网络,再onResponse
怎么把Volly那套移植呢
再想想 :)