Android网络编程随想录(四)

       前面三篇文章从最基础的TCP,HTTP协议理论开始,而后介绍了在Android的开发中所使用的HttpClient和HttpUrlConnection这两种Http客户端。在本文中,咱们一块儿来学习一下在Android开发中常用的volley框架。首先,咱们会从架构的角度了解一下整个框架的结构,而后从源码的角度理解框架实现细节。缓存

       volley是Google在13年发布的一款Android异步网络请求框架。volley有着鲜明的特色:适用于小数据量且频繁的网络请求。这个特色特别适合于Android应用程序的网络操做。另外,咱们从接下来将要介绍的架构中能够发现,volley采用了大量面向接口的设计,保证了整个框架的开放性和灵活性,能够根据不一样的状况需求进行定制。同时,volley也提供了简单的图片加载工具。服务器

       在咱们研究volley框架的结构以前,咱们不妨本身先来思考一下如何实现一款网络操做的框架。首先,咱们根据实际需求设计网络操做请求(无非就是URL及其参数),而后使用多线程并发来执行和处理网络操做请求任务。从服务器中取到数据后,将数据放在内存的cache中以便应用程序使用。网络

       其实volley框架也是如此设计的,以下图所示:多线程

image

       从图中咱们能够看到,整个框架的结构分为4个部分:架构

一、volley使用一个请求队列来管理各类网络请求Request。Request自己是一个描述请求的抽象类,咱们能够根据具体需求状况实现该抽象类。volley也提供了一些Request子类,例如StringRequest,JsonRequest,ImageRequest等等。并发

二、在请求队列RequestQueue中,有两种个轮询分发线程负责对请求任务进行分发调度。第一种是CacheDispatcher,负责调度数据保存在cache中的请求任务;第二种是NetworkDispatcher,负责调度数据在远端服务器上的请求任务。另外,RequestQueue中还有一个叫做ResponseDelivery的接口,用于进行结果分发。请求队列中的网络请求会首先被放入Cache任务队列中,被CacheDispatcher线程调度。CacheDispatcher会试图从cache中取出该任务所请求的数据,若是命中则交给ResponseDelivery解析该数据并返回给应用程序;若是未命中,或者缓存失效等状况下,则将该请求任务加入到网络任务的队列中,供NetworkDispatcher进程调度。NetworkDispatcher请求结束则将结果交给ResponseDelivery做后续的处理。框架

三、从上面的分析中咱们能够看出,咱们所请求的数据主要存在两个个地方:Cache和网络。volley中分别使用Cache和HttpStack这两个接口来描述它们以及所需执行的操做。其中,HttpStack负责处理http网络请求,volley中有两种方式实现了HttpStack接口:基于 HttpURLConnection 的HurlStack 和 基于HttpClient 的HttpClientStack 。而Cache既但是基于SD卡,又能够基于内存。异步

四、经过上面所述的两个接口能够获取并操做咱们请求的数据,这些数据主要分布在网络服务器和本地内存或SD卡中。工具

 

       volley维护了一个请求队列来管理应用程序的网络请求,并采用了单例模式来保证一个应用程序只含有一个请求队列。一般状况下,咱们会继承Application类,并经过newRequestQueue方法来建立一个请求队列。从源码中咱们能够看出,在Android2.3以上使用了基于HttpUrlConnection的HurlStack处理网络请求,而2.3如下使用了基于httpclient的HttpClientStack来处理网络请求。这里的缘由在上一篇文章中咱们提到过,这里再也不赘述。下面咱们顺着请求的提交—>处理—>完成 的这条线路来研究一下框架的内部细节。post

       针对不一样的网络请求,咱们能够实现Request这个抽象类。该抽象类描述了请求的url,方式,head,body以及优先级等等信息。然而volley已经为咱们实现了大部分的子类来知足各类需求。在Request的子类中,咱们须要重写两个方法:

protected Response<T> parseNetworkResponse(NetworkResponse response) :用于将网络返回的字节流解析为合适的数据类型。

protected void deliverResponse(T response) :将解析好的数据传递给它的监听回调。

       另外,若是咱们自定义Request,一般也会重写getBody()方法来构建body内容;若是并未重写getBody方法,那么将会把getParams()方法返回的K-V值拼接起来的字节码做为body。

       定义好了请求Request,接下来咱们来经过源码来研究一下RequestQueue这个类。RequestQueue做为volley框架的核心类,负责管理应用程序的网络请求。咱们在使用volley进行网络的时候,向请求队列提交了Request后发生了什么呢?请看下图。

image

 

       RequestQueue使用一个set来存储一个未处理的请求。当咱们提交一个请求后,RequestQueue会将该请求加入到这个集合中:

private final Set<Request<?>> mCurrentRequests = new HashSet<Request<?>>();

       咱们在上面已经提到过,咱们主要从cache和网络来请求数据。因而,在RequestQueue中维护了两个请求队列:cache请求队列CacheQueue和网络请求队列NetworkQueue:

private final PriorityBlockingQueue<Request<?>> mCacheQueue = new PriorityBlockingQueue<Request<?>>();
private final PriorityBlockingQueue<Request<?>> mNetworkQueue = new PriorityBlockingQueue<Request<?>>();

       咱们能够看到,这两个队列采用了优先阻塞队列PriorityBlockingQueue来维护请求。每一个新请求都会先放入cache队列等待调度,只有在cache未命中或无效的状况下会被放入网络请求队列。可是,若是一个请求在处理的同时,又有相同url的请求怎么办呢?显然重复的请求只要到cache中去取就行了,无需再次进行网络请求,因此volley采用一个map来管理重复的请求,将它们暂时放入map中等待:

private final Map<String, Queue<Request<?>>> mWaitingRequests = new HashMap<String, Queue<Request<?>>>();

       提交了请求以后,接下来的工做就是对请求进行处理了,接下来咱们来研究一下volley的调度策略。

       对应于两种请求队列,分别使用CacheDispatcher和NetworkDispatcher两个线程来调度分发,上面已经介绍过这两种线程了,来看一下RequestQueue初始化和启动的代码:

public void start() {
    stop(); // Make sure any currently running dispatchers are stopped.
    // Create the cache dispatcher and start it.
    mCacheDispatcher = new CacheDispatcher(mCacheQueue, mNetworkQueue, mCache, mDelivery);
    mCacheDispatcher.start();
    // Create network dispatchers (and corresponding threads) up to the pool size.
    for (int i = 0; i < mDispatchers.length; i++) {
        NetworkDispatcher networkDispatcher = new NetworkDispatcher(mNetworkQueue, mNetwork,mCache, mDelivery);
        mDispatchers[i] = networkDispatcher;
        networkDispatcher.start();
    }
}

       从源码中咱们能够看出RequestQueue启动了一个CacheDispatcher线程和多个NetworkDispatcher线程来完成调度分发,下面咱们来研究一下这两种线程。

CacheDispatcher

       CacheDispatcher启动后会不断地轮询mCacheQueue,队列为空时则等待;若是请求的cache未命中,过时或者无效,则会把该请求加入到mNetworkQueue中。当请求处理完成后则会将结果交给ResponseDelivery作最后的处理。具体流程以下:

image

 

NetworkDispatcher

       NetworkDispatcher不断轮询mNetworkQueue取出请求去执行,队列为空则等待,请求处理结束则将结果传递给 ResponseDelivery 去执行后续处理,并判断结果是否要进行缓存。具体流程以下:

 

image

 

       从图中能够看到,不管是CacheDispatcher仍是NetworkDispatcher,请求结束后都会将结果交给ResponseDelivery这个接口来作后续处理,在ResponseDelivery中主要有三个方法还传递请求结果或者错误:

public void postResponse(Request<?> request, Response<?> response) //  用于传递请求结果, request 和 response 参数分别表示请求信息和返回结果信息。
public void postResponse(Request<?> request, Response<?> response, Runnable runnable) //用于传递请求结果,并在完成传递后执行 Runnable
public void postError(Request<?> request, VolleyError error); //用于传输请求错误

       当一个请求处理完成后,首先须要将当前处理集合mCurrentRequests 中的请求移除,而后在重复请求的mWaitingRequests中查询是否有正在等待的重复请求,若是有则放入缓存队列中处理。

总结

       经过从请求的建立—>提交—>处理—>完成 这条主线,本文简单的介绍了volley框架的执行流程以及部分细节。volley的整个框架采用了大量的面向接口的设计,保证了使用的灵活性和框架的开放性。同时,volley又实现了不少接口来帮助开发者应对各类需求,在保证灵活性的同时也减小了不少繁琐的工做。