标签:
OkHttp实现了强大的拦截器机制,它的强大之处在于你可以用它来实现请求监控、请求重写以及重试。以下为一个简单的拦截器实现:
class LoggingInterceptor implements Interceptor {
@Override
public Response intercept(Interceptor.Chain chain) throws IOException {
Request request = chain.request();
long t1 = System.nanoTime();
logger.info(String.format("Sending request %s on %s%n%s",
request.url(), chain.connection(), request.headers()));
Response response = chain.proceed(request);
long t2 = System.nanoTime();
logger.info(String.format("Received response for %s in %.1fms%n%s",
response.request().url(), (t2 - t1) / 1e6d, response.headers()));
return response;
}
}
拦截通过链表来维护的,在实现Interceptor的过程中,必须要调用chain.proceed(request)
,okhttp是通过一个List的来维护的,调用的过程是按顺序来执行的,所以在这期间,如果你要添加一些处理逻辑,一定要把先后执行的这一逻辑考虑进去。
Interceptor又分为普通的应用application interceptor以及network interceptor,这两者是很不相同的。
okhttp本身实现了一套Cache机制,但是并不是我们最终想要的。首先先说下okhttp的Cache实现,它实现了本地缓存(通过LruDiskCache)以及网络请求头缓存。每一个OkHttpClient对应了一个Cache,所以,如果你的应用里面有多个OkHttpClient,建议你公用一个Cache对象,否则,可能会出现Cache混乱,因为OkHttp为了提高效率,Cache内部通过一个链表来维护所有的Response缓存的Key,如果不使用一个Cache,则会出现一个OkHttpClient请求的缓存,使用另外一个OkHttpClient的时候获取不到,因为他们的key在不同的链表里存放。
接着来说下,我们理想的缓存,当没有网络的时候,缓存永远不失效;当有网络的时候如果如果请求失败则会返回缓存,如果请求成功,在会根据缓存设置的有效期,来决定是否访问缓存;同时可以调用刷新缓存,但是刷新缓存之后,新获取的数据依然会使用默认的缓存有效期。以下为通过Interceptor实现的缓存机制:
/**
* 此拦截器为拦截本地缓存,不会对缓存数据造成影响,只会影响到是否能获取到本地缓存数据
*/
public class LocalCacheInterceptor implements Interceptor {
private int maxCacheSeconds;
private Headers commonHeaders;
public LocalCacheInterceptor(int maxCacheSeconds, Headers commonHeaders) {
this.maxCacheSeconds = maxCacheSeconds;
this.commonHeaders = commonHeaders;
}
@Override
public Response intercept(Chain chain) throws IOException {
CacheControl cacheControl = new CacheControl.Builder().maxAge(maxCacheSeconds, TimeUnit.SECONDS)
.maxStale(0, TimeUnit.SECONDS).build();
Request request = chain.request();
Request.Builder builder = request.newBuilder().cacheControl(cacheControl);
if (commonHeaders != null) {
for (String name : commonHeaders.names()) {
builder.addHeader(name, commonHeaders.get(name));
}
}
request = builder.build();
if (AppUtils.isNetworkAvailable()) {
try {
Response response = chain.proceed(request);
if (response.isSuccessful()) {
return response;
}
} catch (Exception e) {
e.printStackTrace();
}
}
//if request failed. always load in cache
cacheControl = new CacheControl.Builder().maxAge(Integer.MAX_VALUE, TimeUnit.SECONDS).maxStale(Integer.MAX_VALUE, TimeUnit.SECONDS).build();
request = builder.cacheControl(cacheControl).build();
return chain.proceed(request);
}
}
/**
* 此拦截器为网络缓存器。只会改变本地缓存时间的大小,不会影响到是否能获取到本地缓存文件
*/
public class NetCacheInterceptor implements Interceptor {
private int maxCacheSeconds;
private Headers commonHeaders;
public NetCacheInterceptor(int maxCacheSeconds, Headers commonHeaders) {
this.maxCacheSeconds = maxCacheSeconds;
this.commonHeaders = commonHeaders;
}
@Override
public Response intercept(Chain chain) throws IOException {
Request request = chain.request();
Request.Builder builder = request.newBuilder();
if (commonHeaders != null) {
for (String name : commonHeaders.names()) {
builder.addHeader(name, commonHeaders.get(name));
}
}
request = builder.build();
Response originalResponse = chain.proceed(request);
// rewrite the response headers to support cache.
if (AppUtils.isNetworkAvailable()) {
return originalResponse.newBuilder()
.header("Cache-Control", "public, max-age=" + EPocketHttpService.DEFAULT_CACHE_MAX_SECONDS)
.build();
} else {
return originalResponse.newBuilder()
.header("Cache-Control", "public, only-if-cached, max-stale=" + Integer.MAX_VALUE)
.build();
}
}
}
private static final Cache OKHTTP_LOCAL_CACHE = new Cache(new File("cahce path"), 100 * 1024 *1024);
...
Headers commonHeaders = Headers.of("auth_token", "...");
OkHttpClient.Builder okHttpBuilder = new OkHttpClient.Builder()
.addInterceptor(new LocalCacheInterceptor(maxCacheSeconds, commonHeaders))
.addNetworkInterceptor(new NetCacheInterceptor(maxCacheSeconds, commonHeaders)).cache(OKHTTP_LOCAL_CACHE);
以上就实现了简单Cache策略。不过需要注意的一条是,OkHttp的Cache是根据URL以及请求参数来生成的,如若需要通过Header来实现,那么可能就需要修改okhttp的源码了。
总体而言,okhttp作为一个网络库来说,已经足够强大,它很纯粹,只是实现了网络请求及缓存,而不会掺杂其它注入返回处理的逻辑。同时,配合Retorfit来使用,简直是一个利器。
标签:
原文地址:http://blog.csdn.net/xsl_bj/article/details/51351913