OkHttp支持 Http1.0/1.1/2/0、SPDY
协议,用来进行客户端和服务器的连接以及数据交互,扮演着传输层的角色。Volley负责处理请求,加载,缓存,线程,同步等问题。先来简单说下Volley的上层部分。用Volley进行网络请求的调用方式如下:
RequestQueue mQueue = Volley.newRequestQueue(Context);
mQueue.start();
StringRequest stringRequest = new StringRequest(...);
mQueue.add(stringRequest);
//添加请求
下面来看一下Volley的部分源码
public static RequestQueue newRequestQueue(Context context, HttpStack stack) {
File cacheDir = new File(context.getCacheDir(), "volley");
String userAgent = "volley/0";
try {
String network = context.getPackageName();
PackageInfo queue = context.getPackageManager().getPackageInfo(network, 0);
userAgent = network + "/" + queue.versionCode;
} catch (NameNotFoundException var6) {
;
}
if(stack == null) {
if(VERSION.SDK_INT >= 9) {
stack = new HurlStack();
} else {
stack = new HttpClientStack(AndroidHttpClient.newInstance(userAgent));
}
}
//由此可见Volley支持自定义网络请求,继承HttpStack即可。Volley+OkHttp整合就是这样的
BasicNetwork network1 = new BasicNetwork((HttpStack)stack);
RequestQueue queue1 = new RequestQueue(new DiskBasedCache(cacheDir), network1);
queue1.start();
return queue1;
}
所有的网络请求都是通过添加到请求队列RequestQueue来执行的,那么RequestQueue执行网络请求的原理又是什么呢?
//线程安全的加减操作
private AtomicInteger mSequenceGenerator;
//等候缓存队列 key->url 如果我们有多个请求的url都是相同的,也就是说请求的资源是相同的,volley就把这些请求放入一个队列,
//在用url做key将队列放入map中。
private final Map<String, Queue<Request<?>>> mWaitingRequests;
//所有在队列中,或者正在被处理的请求都会在这个集合中//缓存队列与网络队列的总和
private final Set<Request<?>> mCurrentRequests;
//缓存请求队列 有阻塞功能//阻塞功能的本质是读取队列中元素调用take()方法中:读写锁,若返回请求为空阻塞线程,直到
//request不为空 返回request,先进先出 PriorityBlockingQueue添加了Lock锁
private final PriorityBlockingQueue<Request<?>> mCacheQueue;
//请求为从网络中直接获取的队列 有阻塞功能
private final PriorityBlockingQueue<Request<?>> mNetworkQueue;
//默认用于网络调度的线程池数目
private static final int DEFAULT_NETWORK_THREAD_POOL_SIZE = 4;
//缓存
private final Cache mCache;
//执行请求的网络
private final Network mNetwork;
//派发请求结果的接口,通过Handler向主线程发送消息private final ResponseDelivery mDelivery;
//该队列的所有网络调度器 多个线程 全部开启 extends Thread
private NetworkDispatcher[] mDispatchers;
//该队列的所有缓存调度器 线程 开启后一直循环调度 extends Thread
private CacheDispatcher mCacheDispatcher;
上边是RequestQueue中所有的全局变量,由这些变量能看出什么吗?RequestQueue添加网络请求可以执行的本质其实是:创建RequestQueue实例,调用start()方法后,a.创建了一个缓存调度器(也就是线程),用来执行已执行且可缓存的网络请求; b.创建了多个网络调度器(也就是线程),用来执行未执行、或者缓存已过期等需要请求服务器的网络请求
public void start() {
this.stop();
// 保证所有正在运行的Dispatcher(也就是线程)都停止
// 创建缓存的派发器(也是一个线程),并启动线程。
this.mCacheDispatcher = new CacheDispatcher(this.mCacheQueue, this.mNetworkQueue, this.mCache, this.mDelivery);
this.mCacheDispatcher.start();
for(int i = 0; i < this.mDispatchers.length; ++i) {
NetworkDispatcher networkDispatcher = new NetworkDispatcher(this.mNetworkQueue, this.mNetwork, this.mCache, this.mDelivery);
this.mDispatchers[i] = networkDispatcher;
networkDispatcher.start();
}
}
下边来看下NetworkDispatcher
,让我们开看看网络调度器是怎么具体执行网络请求的。一般情况下,使用Volley框架,我们会在应用初始化的时候实例RequestQueue并启动,同时启动多个网络调度线程。
public void run() {
Process.setThreadPriority(10);
while(true) {
long startTimeMs;
Request request;
while(true) {
startTimeMs = SystemClock.elapsedRealtime();
try { //请求队列具有阻塞功能
request = (Request)this.mQueue.take();
break;
} catch (InterruptedException var6) {
if(this.mQuit) {
return;
}
}
} try {
request.addMarker("network-queue-take");
if(request.isCanceled()) {
request.finish("network-discard-cancelled");
} else {
this.addTrafficStatsTag(request);
NetworkResponse e = this.mNetwork.performRequest(request); //最终的结果获得
BasicNetwork.performRequest();
request.addMarker("network-http-complete");
if(e.notModified && request.hasHadResponseDelivered()) {
//已有请求结果,并且有效
request.finish("not-modified");
} else {
Response volleyError1 = request.parseNetworkResponse(e);
//解析响应结果 eg:JsonObjectRequest.parseNetworkResponse 解析为Json
request.addMarker("network-parse-complete");
if(request.shouldCache() && volleyError1.cacheEntry != null) {
//缓存结果
this.mCache.put(request.getCacheKey(), volleyError1.cacheEntry);
request.addMarker("network-cache-written");
}
request.markDelivered();
//result->hasHadResponseDelivered()==true
this.mDelivery.postResponse(request, volleyError1);
}
}
} catch (VolleyError var7) {
var7.setNetworkTimeMs(SystemClock.elapsedRealtime() - startTimeMs);
this.parseAndDeliverNetworkError(request, var7);
} catch (Exception var8) {
VolleyLog.e(var8, "Unhandled exception %s", new Object[]{var8.toString()});
VolleyError volleyError = new VolleyError(var8);
volleyError.setNetworkTimeMs(SystemClock.elapsedRealtime() - startTimeMs);
this.mDelivery.postError(request, volleyError);
}
}
}
BasicNetwork.performRequest(request)又是怎么获取结果的呢?
public NetworkResponse performRequest(Request<?> request) throws VolleyError {
long requestStart = SystemClock.elapsedRealtime();
while(true) {
HttpResponse httpResponse = null;
Object responseContents = null;
Map responseHeaders = Collections.emptyMap();
try {
HashMap e = new HashMap();
this.addCacheHeaders(e, request.getCacheEntry());
httpResponse = this.mHttpStack.performRequest(request, e);
//Boss来了,It's here;
StatusLine statusCode1 = httpResponse.getStatusLine();
int networkResponse1 = statusCode1.getStatusCode();
...
}
}
}
具体的就不在这里说明了。那么如果想用Volley的上层,OkHttp的底层,又怎么来实现呢?最终请求是通过调用HttpStack.performRequest()得到响应结果的,这个HttpStack是在实例RequestQueue时赋值的。再回头看下之前的代码。
public static RequestQueue newRequestQueue(Context context, HttpStack stack) {
...
if(stack == null) {
if(VERSION.SDK_INT >= 9) {
stack = new HurlStack();
} else {
stack = new HttpClientStack(AndroidHttpClient.newInstance(userAgent));
}
}
...
}
所以只需要继承HttpStack(如 OkHttp3Stack),重写performRequest() 方法,实例RequestQueue时使用 OkHttp3Stack即可。 详情之后继续分析。
网友评论