Volley框架解析
Volley是 Google 推出的Android异步网络请求框架和图片加载框架,它既可以像AsyncHttpClient一样非常简单地进行HTTP通信,也可以像Universal-Image-Loader一样轻松加载网络上的图片。特别适合数据量小,通信频繁的网络操作,而对于大数据量的网络操作,比如说下载大量的文件等,Volley的表现就不好了,可以使用DownloadManager。
Volley的主要特点
(1)扩展性强。Volley 中大多是基于接口的设计,可配置性强。
(2) 一定程度符合 Http 规范,包括返回ResponseCode(2xx、3xx、4xx、5xx)的处理,请求头的处理,缓存机制的支持等。并支持重试及优先级定义。
(3)默认 Android在Android 2.2版本之前,HttpClient拥有较少的bug,API众多,而且实现比较稳定,因此使用它是最好的选择。而在Android 2.3版本及以后,HttpURLConnection则是最佳的选择。它的API简单,体积较小,因而非常适用于Android项目。压缩和缓存机制可以有效地减少网络访问的流量,在提升速度和省电方面也起到了较大的作用。对于新的应用程序应该更加偏向于使用HttpURLConnection,因为在以后的工作当中我们也会将更多的时间放在优化HttpURLConnection上面。2.3 及以上基于 HttpURLConnection,2.3 以下基于 HttpClient 实现,
(4)提供简便的图片加载工具。
它提供ImageLoader加载图片,明显要比ImageRequest更加高效,因为它不仅可以帮我们对图片进行缓存,还可以过滤掉重复的链接,避免重复发送请求,从源码中看到他的使用过程如下:
a. 创建一个RequestQueue对象。
b. 创建一个ImageLoader对象。
c. 获取一个ImageListener对象。
d. 调用ImageLoader的get()方法加载网络上的图片。
Volley架构图
Volley原理图
在主线程中调用RequestQueue的add()方法来添加一条网络请求,这条请求会先被加入到缓存队列当中,如果发现可以找到相应的缓存结果就直接读取缓存并解析,然后回调给主线程。如果在缓存中没有找到结果,则将这条请求加入到网络请求队列中,然后处理发送HTTP请求,解析响应结果,写入缓存,并回调主线程。
Volley类图
Volley使用
1.使用前要在AndroidManifesr.xml中配置使用权限<uses-permission android:name="android.permission.INTERNET" />
2.可以从git上下载
git clone https://android.googlesource.com/platform/frameworks/volley
或者下载Volley.jar包,并导入Add As Library
也可以在build.gradle文件中添加依赖:
compile 'com.android.volley:volley:1.0.0'
3. (1)创建RequestQueue对象
(2)创建xxRequest请求对象
(3)将xxRequest请求对象加入RequestQueue对象中,使用示例如下:
public void getHomePageData(Context context, final VolleyCallback callback) { String jsonUrl = RPCRequestManager.generateJsonUrl(typeURL, path).trim(); RequestQueue mRequestQueue = Volley.newRequestQueue(context); JsonObjectRequest req = new JsonObjectRequest(jsonUrl, null, new Response.Listener<JSONObject>() { @Override public void onResponse(JSONObject response) { } }, new Response.ErrorListener() { @Override public void onErrorResponse(VolleyError error) { VolleyLog.e("Error: ", error.getMessage()); } }); req.setShouldCache(false); mRequestQueue.add(req); } |
Volley源码
网络操作全部是在子线程中处理的,我们不必担心阻塞UI线程。网络请求的结果会异步返回给我们,我们只需要处理Request的回调即可。我们从源码中看网络请求的处理:
在Volley.class中,
在第39行判断如果stack是等于null的,则去创建一个HttpStack对象,这里会判断如果手机系统版本号是大于9的,则创建一个HurlStack的实例,否则就创建一个HttpClientStack的实例。实际上HurlStack的内部就是使用HttpURLConnection进行网络通讯的,而HttpClientStack的内部则是使用HttpClient进行网络通讯的,创建好了HttpStack之后,接下来又创建了一个Network对象,它是用于根据传入的HttpStack对象来处理网络请求的,紧接着new出一个RequestQueue对象,并调用它的start()方法进行启动,然后将RequestQueue返回。跟踪start,进入RequestQueue.class:
先创建了一个CacheDispatcher的实例,然后调用了它的start()方法,接着在一个for循环里去创建NetworkDispatcher的实例,并分别调用它们的start()方法。这里的CacheDispatcher和NetworkDispatcher都是继承自Thread的,而默认情况下for循环会执行四次,也就是说当调用了Volley.newRequestQueue(context)之后,就会有五个线程一直在后台运行,不断等待网络请求的到来,其中CacheDispatcher是缓存线程,NetworkDispatcher是网络请求线程。得到了RequestQueue之后,我们只需要构建出相应的Request,然后调用RequestQueue的add()方法将Request传入就可以完成网络请求操作了,同类下的add()方法中
在第131行的时候会判断当前的请求是否可以缓存,如果不能缓存则在第132行直接将这条请求加入网络请求队列,可以缓存的话则在第151行将这条请求加入缓存队列。在默认情况下,每条请求都是可以缓存的,我们也可以调用Request的setShouldCache(false)方法来改变这一默认行为。既然默认每条请求都是可以缓存的,被添加到了缓存队列中,于是一直在后台等待的缓存线程就要开始运行,进入到CacheDispatcher中的run()方法,
在52行中while(true)死循环,说明网络请求线程也是在不断运行的在第71行的时候会调用Network的performRequest()方法来去发送网络请求,而Network是一个接口,这里具体的实现是BasicNetwork,看下它的performRequest()方法,
在NetworkDispatcher中收到了NetworkResponse这个返回值后又会调用Request的parseNetworkResponse()方法来解析NetworkResponse中的数据,以及将数据写入到缓存,这个方法的实现是交给Request的子类来完成的,因为不同种类的Request解析的方式也肯定不同。在解析完了NetworkResponse中的数据之后,又会调用ExecutorDelivery的postResponse()方法来回调解析出的数据,
在mResponsePoster的execute()方法中传入了一个ResponseDeliveryRunnable对象,就可以保证该对象中的run()方法就是在主线程当中运行的。
其中在第62行调用了Request的deliverResponse()方法,每一条网络请求的响应都是回调到这个方法中,最后我们再在这个方法中将响应的数据回调到Response.Listener的onResponse()方法中就可以了。
RequestQueue
顾名思义,它是一个请求队列,并发地发出这些请求,因此我们不必为每一次HTTP请求都创建一个RequestQueue对象,xxRequest提供三参数和四参数的构造函数,对三参数的构造函数,第一个参数就是目标服务器的URL地址,第二个参数是服务器响应成功的回调,第三个参数是服务器响应失败的回调。在四参数的构造函数中,可以设置请求类型:post或get,默认是get请求。将xxRequest对象添加到RequestQueue里面。当HTTP通信完成之后,服务器响应的数据信息就会回调到onResponse()方法中,parseNetworkResponse()方法是对服务器响应的数据进行解析,其中数据是以字节的形式存放在NetworkResponse的data变量中,将数据取出后组装成一个类型,并传入Response的success()方法中即可。
自定义Request
我们亦可以通过自己定义请求继承自Request类,实现对应的方法即可,就不做过多介绍。