Android网络编程随想录(四)

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

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

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

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

从图中我们可以看到,整个框架的结构分为4个部分:

1、volley使用一个请求队列来管理各种网络请求Request。Request本身是一个描述请求的抽象类,我们可以根据具体需求情况实现该抽象类。volley也提供了一些Request子类,例如StringRequest,JsonRequest,ImageRequest等等。

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

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

4、通过上面所述的两个接口可以获取并操作我们请求的数据,这些数据主要分布在网络服务器和本地内存或SD卡中。

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

针对不同的网络请求,我们可以实现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后发生了什么呢?请看下图。

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做最后的处理。具体流程如下:

NetworkDispatcher

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

从图中可以看到,无论是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又实现了很多接口来帮助开发者应对各种需求,在保证灵活性的同时也减少了很多繁琐的工作。

时间: 2024-08-28 08:48:39

Android网络编程随想录(四)的相关文章

Android网络编程(四)从源码解析volley

相关文章 Android网络编程(一)HTTP协议原理 Android网络编程(二)HttpClient与HttpURLConnection Android网络编程(三)Volley用法全解析 1.volley结构图 从上图可以看到volley分为三个线程,分别是主线程.缓存调度线程.和网络调度线程,首先请求会加入缓存队列,如果发现可以找到相应的缓存结果就直接读取缓存并解析,然后回调给主线程:如果在缓存中没有找到结果,则将这条请求加入到网络队列中,然后发送HTTP请求,解析响应并写入缓存,并回调

Android网络编程随想录(2)

上篇文章介绍了传输层TCP协议的理论知识,本文主要介绍了TCP协议基础之上HTTP协议和HTTPS协议的理论知识. HTTP协议基于TCP协议定义了客户端向服务器请求数据的方式,它是面向事务的应用层协议具有灵活.简单快速.无连接和无状态的特点,是网络中交换各类数据的基础. HTTP协议的请求与响应报文 HTTP报文的格式如下所示: 我们可以看出,HTTP协议的报文主要分为报文首部和报文主体两部分,中间用空行隔开.下面让我们详细介绍一下请求报文和响应报文: 请求报文 请求报文由三部分组成:请求行,

Android网络编程随想录(3)

大多数Android的app都会使用HTTP协议来发送和接收数据.在Android开发中,通常使用两种http客户端:一个是Apache的HttpClient,另一个是HttpURLConnection.这两种HTTP客户端API都支持HTTPS协议,流数据上传和下载,配置超时,IPV6协议以及连接池等等. Apache HttpClient HttpClient的API众多,并且bug少比较稳定.但是,HttpClient的API比较大,很难在保证兼容性的前提下去对其进行扩展.所以很多Andr

Android网络编程(一)HTTP协议原理

相关文章 Android网络编程(一)HTTP协议原理 Android网络编程(二)HttpClient与HttpURLConnection Android网络编程(三)Volley使用方法全解析 Android网络编程(四)从源代码解析volley Android网络编程(五)OkHttp2.x使用方法全解析 Android网络编程(六)OkHttp3使用方法全解析 Android网络编程(七)源代码解析OkHttp前篇[请求网络] Android网络编程(八)源代码解析OkHttp后篇[复用

Android网络编程(十一)源码解析Retrofit

相关文章 Android网络编程(一)HTTP协议原理 Android网络编程(二)HttpClient与HttpURLConnection Android网络编程(三)Volley用法全解析 Android网络编程(四)从源码解析volley Android网络编程(五)OkHttp2.x用法全解析 Android网络编程(六)OkHttp3用法全解析 Android网络编程(七)源码解析OkHttp前篇[请求网络] Android网络编程(八)源码解析OkHttp后篇[复用连接池] Andr

Android网络编程(七)源码解析OkHttp前篇[请求网络]

相关文章 Android网络编程(一)HTTP协议原理 Android网络编程(二)HttpClient与HttpURLConnection Android网络编程(三)Volley用法全解析 Android网络编程(四)从源码解析volley Android网络编程(五)OkHttp2.x用法全解析 Android网络编程(六)OkHttp3用法全解析 前言 学会了OkHttp3的用法后,我们当然有必要来了解下OkHttp3的源码,当然现在网上的文章很多,我仍旧希望我这一系列文章篇是最简洁易懂

Android网络编程(六)OkHttp3用法全解析

相关文章 Android网络编程(一)HTTP协议原理 Android网络编程(二)HttpClient与HttpURLConnection Android网络编程(三)Volley用法全解析 Android网络编程(四)从源码解析volley Android网络编程(五)OkHttp2.x用法全解析 前言 上一篇介绍了OkHttp2.x的用法,这一篇文章我们来对照OkHttp2.x版本来看看,OkHttp3使用起来有那些变化.当然,看这篇文章前建议看一下前一篇文章Android网络编程(五)O

Android网络编程(五)OkHttp用法全解析

相关文章 Android网络编程(一)HTTP协议原理 Android网络编程(二)HttpClient与HttpURLConnection Android网络编程(三)Volley用法全解析 Android网络编程(四)从源码解析volley 前言 讲完了Volley,我们接下来看看目前比较火的网络框架OkHttp, 它处理了很多网络疑难杂症:会从很多常用的连接问题中自动恢复.如果您的服务器配置了多个IP地址,当第一个IP连接失败的时候,OkHttp会自动尝试下一个IP,此外OkHttp还处理

Android网络编程系列 一 TCP/IP协议族

在学习和使用Android网路编程时,我们接触的仅仅是上层协议和接口如Apache的httpclient或者Android自带的httpURlconnection等等.对于这些接口的底层实现我们也有必要进一步的了解,这就要我们了解网络通信层了,提到网络通信层不得不说起ISO-OSI的七层协议经典架构,如图所示: 上图的左边部分就是osi架构模型了, ISO/OSI模型,即开放式通信系统互联参考模型(Open System Interconnection Reference Model),是国际标