【Android】Volley网络框架的学习及源码分析

介绍

Volley是Google在2013年发布的一款Android平台上的网络请求库。

它有如下特点:

  • 使得网络通信更快,更简单
  • GET、POST网络请求及网络图像的高效异步处理请求
  • 可以对网络请求进行排序优先级处理
  • 网络请求的缓存
  • 多级别取消请求
  • 与Activity生命周期的联动

但它也有一定缺点:

  • 不适合进行数据的上传与下载

Volley的使用

建立全局请求队列

首先我们需要一个全局的Application来建立一个全局的请求队列。在这里我们建立一个ContextApplication并继承自Application。并在manifest中指定application的name属性为ContextApplication。

然后我们在ContextApplication中写用于建立请求队列的代码。

这样就完成了全局请求队列的建立。

GET请求

首先我们学习用StringRequest来请求数据。

此处我们将请求方法设置为了Method.GET,然后填入请求链接,创建请求成功及失败的回调。

之后我们为request设置了一个tag,这样在加入全局队列后可以通过标签找到这个request。

之后将该request放入全局队列。这样一个使用StringRequest的GET请求就成功完成了

如果换做是JsonObjectRequest,基本相同,仅仅是最后的结果返回的是JsonObject而已。传入需要多传入一个JsonObject参数。这个参数是用于POST请求,GET请求可以设置为null

可以看出,相比HttpUrlConnection,Volley实现请求确实简单了不少。

POST请求

用StringRequest进行POST请求,参数与之前大致相同,将方法改为POST。然后传递参数通过实现它的传递参数方法,也就是getParams方法。

可以看到,getParams方法返回的是一个Map,因此我们需要建立一个Map,然后将参数添加到Map中,最后返回该map。

这样就完成了用StringRequest进行POST请求。

如果我们换为使用JsonObjectRequest进行请求,那么我们需要在外部建立一个Map,将参数像刚刚那样传递,然后建立一个JsonObject,将Map放入。最后将jsonObject作为参数传入JsonObjectRequest的构造函数即可。

将Volley生命周期与Activity进行关联。

我们只需在Activity的onStop方法,通过cancelAll方法传入tag,将请求关闭即可。

网络图片的加载

网络图片加载需要用到ImageRequest。它需要传入的第一个参数是图片的url,然后是请求成功的回调,之后是图片的最大宽度以及最大高度(设置为0会以原图方式加载)。然后是加载图片的格式,这里选择Config.RGB_565。之后是加载失败的回调。

最后将请求放入队列即可完成网络图片的加载。

图片的缓存加载

这里我们使用ImageLoader来进行加载图片。这里需要填入的参数是请求队列以及缓存。

请求队列我们填入全局的队列。而ImageCache本身是起不到作用的,我们需要结合LruCache来使用。

我们自定义一个BitmapCache类,实现ImageCache接口。可以看到,它需要实现getBitmap以及putBitmap方法,通过这两个方法,我们就可以实现图片的缓存。加载图片时,会先从缓存中获取图片,获取不到再从网络获取图片。

之后我们通过构造方法创建ImageLoader,创建好ImageLoader之后,通过ImageLoader的getImageListener方法获取到ImageListener。之后通过imageLoader的get方法进行加载即可。

Volley的源码分析

参考自郭霖大神的博客:http://blog.csdn.net/guolin_blog/article/details/17656437

要解析Volley的源码,我们从第一个用到的方法——newRequestQueue方法来看起,查看newRequestQueue的代码

可以看到,这里在第10行判断如果stack是等于null的,则去创建一个HttpStack对象,这里会判断如果手机系统版本号是大于9的,则创建一个HurlStack的实例,否则就创建一个HttpClientStack的实例。

实际上HurlStack的内部就是使用HttpURLConnection进行网络通讯的,而HttpClientStack的内部则是使用HttpClient进行网络通讯的 。

创建好了HttpStack之后,接下来又创建了一个Network对象,它是用于根据传入的HttpStack对象来处理网络请求的,紧接着new出一个RequestQueue对象,并调用它的start()方法进行启动,然后将RequestQueue返回,这样newRequestQueue()的方法就执行结束了。

那么RequestQueue的start()方法内部到底执行了什么东西呢?我们跟进去:

这里先创建了一个CacheDispatcher的实例,然后调用了它的start()方法,接着在一个for循环里去创建NetworkDispatcher的实例,并分别调用它们的start()方法。

这里的CacheDispatcher和NetworkDispatcher都是继承自Thread的,而默认情况下for循环会执行四次,也就是说当调用了Volley.newRequestQueue(context)之后,就会有五个线程一直在后台运行,不断等待网络请求的到来,其中CacheDispatcher是缓存线程,NetworkDispatcher是网络请求线程。

我们得到RequestQueue后,构建出相应的Request,然后调用RequestQueue的add方法即可完成网络请求,我们可以进入add方法看看。

可以看到,在第11行的时候会判断当前的请求是否可以缓存,如果不能缓存则在第12行直接将这条请求加入网络请求队列,可以缓存的话则在第33行将这条请求加入缓存队列。

由此可见,在默认情况下,每条请求都是可以缓存的,当然我们也可以调用Request的setShouldCache(false)方法来改变这一行为。

既然默认每条请求都是可以缓存的,自然就被添加到了缓存队列中,于是一直在后台等待的缓存线程就要开始运行起来了,我们可以查看CacheDispatcher中的run()方法:

run方法中代码比较长,我们可以在11行看到一个while循环,说明这个缓存线程是始终运行的。在32行可以看到在从缓存中取出响应的结果。如果缓存结果为空,就把这条请求加入网络请求队列。不为空的情况下则判断缓存是否过期,过期的话仍然将这条请求加入网络请求队列。否则不需要网络请求,直接使用缓存中的数据。

第39行在调用Request的parseNetworkResponse()方法来对数据进行解析 。之后则是将解析后的数据进行回调。回调的部分我们在这里暂时不介绍,因为它和NetworkDispatcher的逻辑基本相同,等到后面一起分析。

我们来到NetWorkDIspatcher来查看它如何处理网络请求队列。

可以看到,NetworkDispatcher中也是while(true)循环,说明网络请求的线程也是不断运行。看到28行会调用Network的performRequest()方法来发送网络请求。而Network是一个接口,这里具体的实现是BasicNetwork,我们来看下它的performRequest()方法:

这段方法中大多都是一些网络请求细节方面的东西,我们并不需要太多关心。需要注意在14行调用了HttpStack的performRequest()方法。

这里的HttpStack就是在一开始调用newRequestQueue()方法是创建的实例,默认情况下如果系统版本号大于9就创建的HurlStack对象,否则创建HttpClientStack对象。前面提到,这两个对象的内部分别使用HttpURLConnection和HttpClient来发送网络请求,我们不再需要跟进查看。获取结果之后会将服务器返回的数据组装成一个NetworkResponse对象进行返回。

在NetworkDispatcher中收到了NetworkResponse这个返回值后又会调用Request的parseNetworkResponse()方法来解析NetworkResponse中的数据,以及将数据写入到缓存,这个方法的实现是交给Request的子类来完成的,因为不同种类的Request解析的方式也肯定不同。

在解析完了NetworkResponse中的数据之后,又会调用ExecutorDelivery的postResponse()方法来回调解析出的数据:

其中,在mResponsePoster的execute()方法中传入了一个ResponseDeliveryRunnable对象,就可以保证该对象中的run()方法就是在主线程当中运行的了,我们看下run()方法中的代码:

在第22行调用了Request的deliverResponse()方法。每一条网络请求的响应都是回调到这个方法中,最后我们再在这个方法中将响应的数据回调到Response.Listener的onResponse()方法中就可以了。

以下是Volley库中自带的一张Volley原理图:

Volley

其中蓝色部分代表主线程,绿色部分代表缓存线程,橙色部分代表网络线程。我们在主线程中调用RequestQueue的add()方法来添加一条网络请求,这条请求会先被加入到缓存队列当中,如果发现可以找到相应的缓存结果就直接读取缓存并解析,然后回调给主线程。如果在缓存中没有找到结果,则将这条请求加入到网络请求队列中,然后处理发送HTTP请求,解析响应结果,写入缓存,并回调主线程。

评 论 区

  1. 还没有任何评论,你来说两句吧

发表评论

%d 博主赞过: