深入Volley之前,有必要回顾下几个知识点:
1.HTTP0.9 -> HTTP1.0 ->HTTP1.1 ->HTTP2协议[注:为什么不是2.0,协议制定委员会说以后只存在HTTPX];Google—HTTP协议;
2.HTTP2优点:相比较HTTP1.1主要两大改进:1.可复用TCP连接;2.所有报文信息都将是二进制传输,采用GZIP或COMPRESS压缩方式;有必要百度下这两点的实际原理;
3.目前为什么国内很多网站没有HTTP全站替换HTTPS,速度是主要原因:想想SSL和TLS的握手还要加上HTTP默认TCP三次握手,测试显示增加访问时间3倍左右;
说明:本文不会具体分析每个类的作用。[每个类都很优美,例如ByteArrayPool这个类]
目前为止除了OkHttp的框架,个人认为遇到的最优秀网络请求框架,本文仅从以下几点谈下Volley:
1,高度可扩展性(支持https )
2,重定向url问题
3,协议内容类型 传参问题
4,Cache缓存机制
5,对大多数客户端封装的Volley数据展示层向上层抛出数据修改意见
1.高度可扩展性(支持https )
if (stack == null) {
if (Build.VERSION.SDK_INT >= 9) {
stack = new HurlStack();
} else {
// Prior to Gingerbread, HttpUrlConnection was unreliable.
// See: http://android-developers.blogspot.com/2011/09/androids-http-clients.html stack = new HttpClientStack(AndroidHttpClient.newInstance(userAgent));
}
}
volley提供了HttpStack抽象类,极大的扩展性,方便接入HttpURLConnection | OKHTTP等;在Android2.3之前,使用AndroidHttpClient是由于HttpURLConnection调用 close() 函数会影响连接池,导致连接复用失效,若使用需要关闭keepAlive,极大的不方便,每次HTTP请求都有。另外在HttpURLConnection 默认开启了 gzip 压缩,提高了 HTTPS 的性能,Android4.0 HttpURLConnection 支持了请求结果缓存。
2.重定向url问题
BasicNetwork.performRequest方法
// Handle moved resourcesif (
statusCode == HttpStatus.SC_MOVED_PERMANENTLY || statusCode == HttpStatus.SC_MOVED_TEMPORARILY) {
String newUrl = responseHeaders.get("Location");
request.setRedirectUrl(newUrl)
; }
这里可能会有问题,对于业务约定的只重定向GET请求且参数或Cookie不变的话没有问题,否则需要手动修改重定向参数;
3.协议内容类型
传参问题Content-Type问题[参考http://www.alloyteam.com/2015/06/yong-volley-cai-di-keng/]
4,Cache缓存机制
[参考:http://www.a.codekk.com/detail/Android/grumoon/Volley%20源码解析]
Volley 构建了一套相对完整的符合 Http 语义的缓存机制。
优点和特点
(1). 根据Cache-Control和Expires首部来计算缓存的过期时间。如果两个首部都存在情况下,以Cache-Control为准。
(2). 利用If-None-Match和If-Modified-Since对过期缓存或者不新鲜缓存,进行请求再验证,并处理 304 响应,更新缓存。
(3). 默认的缓存实现,将缓存以文件的形式存储在 Disk,程序退出后不会丢失。缓存的再验证方面,在构建If-Modified-Since请求首部时,Volley 使用了服务端响应的Date首部,没有使用Last-Modified首部。整个框架没有使用Last-Modified首部。这与 Http 语义不符。private void addCacheHeaders(Mapheaders, Cache.Entry entry) { // If there's no cache entry, we're done. if (entry == null) { return; } if (entry.etag != null) { headers.put("If-None-Match", entry.etag); } if (entry.serverDate > 0) { Date refTime = new Date(entry.serverDate); headers.put("If-Modified-Since", DateUtils.formatDate(refTime)); }}服务端根据请求时通过If-Modified-Since首部传过来的时间,判断资源文件是否在If-Modified-Since时间 以后 有改动,如果有改动,返回新的请求结果。如果没有改动,返回 304 not modified。Last-Modified代表了资源文件的最后修改时间。通常使用这个首部构建If-Modified-Since的时间。Date代表了响应产生的时间,正常情况下Date时间在Last-Modified时间之后。也就是Date>=Last-Modified。通过以上原理,既然Date>=Last-Modified。那么我利用Date构建,也是完全正确的。可能的问题出在服务端的 Http 实现上,如果服务端完全遵守 Http 语义,采用时间比较的方式来验证If-Modified-Since,判断服务器资源文件修改时间是不是在If-Modified-Since之后。那么使用Date完全正确。可是有的服务端实现不是比较时间,而是直接的判断服务器资源文件修改时间,是否和If-Modified-Since所传时间相等。这样使用Date就不能实现正确的再验证,因为Date的时间总不会和服务器资源文件修改时间相等。尽管使用Date可能出现的不正确情况,归结于服务端没有正确的实现 Http 语义。但我还是希望 Volley 也能完全正确的实现 Http 语义,至少同时处理Last-Modified和Date,并且优先使用Last-Modified。
5,对大多数客户端封装的Volley数据展示层向上层抛出数据修改意见
目前响应靠new Thread向上抛数据会极大地可能造成线程竞争或死锁,同样也会内存抖动问题;/** 响应监听 **/ private ListenerresponseListener = new Listener() { @Override public void onResponse(final T response) { if (mCanceled) { // 如果取消了,直接返回 return; } new Thread(new Runnable() { @Override public void run() { Message message = mHandler.obtainMessage(); message.obj = onNetResponse(response); mHandler.sendMessage(message); } }).start(); } };建议实现线程池来处理,参考Volley的ExecutorDelivery类设计思想private ExecutorPostResult mExecutorPostResult = new ExecutorPostResult(new Handler(Looper.getMainLooper()));/** 响应监听 **/ private ListenerresponseListener = new Listener() {
@Override
public void onResponse(final T response) {
if (mCanceled) {
// 如果取消了,直接返回
return;
}
// 由于解析需要时间,启动子线程
mExecutorPostResult.postResponseResult(SuningNetTask.this,onNetResponse(response));
}
};