google的volley框架下载为什么没用线程池

网络连接之——谷歌提供的通信框架Volley【避免创建多个线程对象】
网络连接之——谷歌提供的通信框架Volley【避免创建多个线程对象】
如今,android应用不可避免会用到网络技术,而常用的就是HttpURLConnection和HttpClient。
但HttpURLConnection和HttpClient的用法还是稍微有些复杂的,如果不进行适当封装的话,很容易就会写出不少重复代码。于是乎,一些Android网络通信框架也就应运而生,比如说AsyncHttpClient,它把HTTP所有的通信细节全部封装在了内部,我们只需要简单调用几行代码就可以完成通信操作了。再比如Universal-Image-Loader,它使得在界面上显示网络图片的操作变得极度简单,开发者不用关心如何从网络上获取图片,也不用关心开启线程、回收图片资源等细节,Universal-Image-Loader已经把一切都做好了。
Android开发团队也是意识到了有必要将HTTP的通信操作再进行简单化,于是在2013年Google I/O大会上推出了一个新的网络通信框架——Volley。Volley可是说是把AsyncHttpClient和Universal-Image-Loader的优点集于了一身。
想要详细了解volley可以,查看源码包:
不用再自己创建线程,本身存在线程池。
其中蓝色的是主线程,绿色的是缓存线程,黄色的是网络线程
1.当一个Request请求添加到RequestQueue请求队列中,Volley就开始工作了。RequestQueue请求队列中持有一个CacheDispatcher缓存管家和一组NetworkDispatcher网络管家。
2.RequestQueue会先叫来CacheDispatcher缓存管家,让他去看看,当前请求的数据在没在cache中。
2.1.当前的数据在cache中,那就把数据从cache中取出来,然后经过一番加工,将加工好的数据交付给主线程
2.2.当前数据没在cache中,进行第3步
3.进行到了这一步,那肯定是数据没有在缓存中,那只能去网络中获取了,这时候RequestQueue会叫来NetworkDispatcher,NetworkDispatcher可是有一帮呢,其实这是一个线程池,默认情况下会启动4个线程去网络下载数据。所以RequestQueue把当前闲着的NetworkDispatcher叫来,给他们分配任务。
4.拿到任务的NetworkDispatcher就会去网络上下载数据了,与此同时,他会判断下载到的数据能否写入到cache缓存中,如果可以的话就写入cache,以便于下一次直接从cache中获取到数据。最后,将数据加工,交付给主线程。
1)下载Volley:
eclipse:下载jar包,复制到工程下的libs中即可。
法1:和eclipse一样把jar包放在libs下
法2:用studio直接下载:右击项目&open moudle settings&在Dependencies中搜索:volley,使用最新的版本,OK即可。
法3:导入源码包:file&右击import module &找到源码包路径&确定。
还需要导入module,在Dependencies&点击+号导入modul
stdio中导包的这种方式,也可以用来导入httpclient包,因为在android6.0中舍弃了httpclient,可以在6.0搜索:org.apache.http导入httpclient包即可。
2)使用步骤:
创建请求队列:
RequestQueue queue = Volley.newRequestQueue(getApplicationContext());
创建http请求:
//可以传入三个参数或四个参数(请求方式,url,请求成功的监听,请求错误的监听)
StringRequest request = new StringRequest(,,,)
- 将请求添加到请求队列中:
queue.add(request)
不要忘了,这里连接网络需要权限:
android:name="android.permission.INTERNET"/&
功能:连接百度网页,将返回信息显示到textview中。
5.改进:采用单例模式
我们使用Volley是由于它不像Httpclient或其他网络连接那样,每次点击都会创建一个线程,但现在的问题是:每次点击都会创建一个请求队列。
这不是我们想要的效果,所以这里采用单例的方式使一个应用程序只有一个请求队列。至于单例的类,android的API中也给出了,这里我们列出来,以后可以直接使用即可。
1)单例请求队列的类:
import android.content.C
import android.graphics.B
import android.util.LruC
import com.android.volley.R
import com.android.volley.RequestQ
import com.android.volley.toolbox.ImageL
import com.android.volley.toolbox.V
* Created by zhonghangIT on .
public class MySingleton {
private static MySingleton mI
private RequestQueue mRequestQ
private ImageLoader mImageL
private static Context mC
private MySingleton(Context context) {
mRequestQueue = getRequestQueue();
mImageLoader = new ImageLoader(mRequestQueue,
new ImageLoader.ImageCache() {
private final LruCache&String, Bitmap&
cache = new LruCache&String, Bitmap&(20);
public Bitmap getBitmap(String url) {
return cache.get(url);
public void putBitmap(String url, Bitmap bitmap) {
cache.put(url, bitmap);
public static synchronized MySingleton getInstance(Context context) {
if (mInstance == null) {
mInstance = new MySingleton(context);
public RequestQueue getRequestQueue() {
if (mRequestQueue == null) {
mRequestQueue = Volley.newRequestQueue(mCtx.getApplicationContext());
return mRequestQ
public &T& void addToRequestQueue(Request&T& req) {
getRequestQueue().add(req);
public ImageLoader getImageLoader() {
return mImageL
2)volley单例时的使用:
android:name="android.permission.INTERNET"/&
6.Volley中自带的Network ImageView(下载图片)
Network ImageView方法获得图片的方法,现在都一般不用,一般采用ImageLoader的方式。
1)xml布局中的图片要用Network ImageView:
&com.android.volley.toolbox.NetworkImageView
android:id="@+id/netimageview"
android:layout_width="match_parent"
android:layout_height="wrap_content"
&/com.android.volley.toolbox.NetworkImageView&
2)Network ImageView的使用(采用单例)
networkImageView.setImageUrl("http://adress of img",MySingleton.getInstance(this).getImageLoader())
我的热门文章
即使是一小步也想与你分享&&&&好吧,这个框架早就出来了,你现在才介绍是不是有点多余?呵呵,我只能说大神飘过吧。前言Volley,它是2013年Google I/O上发布的一款网络框架,基于Android平台,能使网络通信更快,更简单,更健全。&&&&一句话概括:小而快!优缺点优点:(1)默认Android2.3及以上基于HttpURLConnection,2.3以下使用基于HttpClient;&(2)符合Http&缓存语义&的缓存机制(提供了默认的磁盘和内存等缓存);(3)请求队列的优先级排序;(4)提供多样的取消机制;(5)提供简便的图片加载工具(其实图片的加载才是我们最为看重的功能);(6)&一个优秀的框架&。缺点:它只适合数据量小,通信频繁的网络操作,如果是数据量大的,像音频,视频等的传输,还是不要使用Volley的为好。对比下面是百度出来的各个框架的对比:&&&&volley:是一个简单的异步http库,仅此而已。缺点是不支持同步,这点会限制开发模式;不能post大数据,所以不适合用来上传文件。&&&&android-async-http:与volley一样是异步网络库。但volley是封装的httpUrlConnection,它是封装的httpClient,而android平台不推荐用HttpClient了,所以这个库已经不适合android平台了。&&&&okhttp:是高性能的http库,支持同步、异步,而且实现了spdy、http2、websocket协议,api很简洁易用,和volley一样实现了http协议的缓存。picasso就是利用okhttp的缓存机制实现其文件缓存,实现的很优雅,很正确,反例就是UIL(universal image loader),自己做的文件缓存,而且不遵守http缓存机制。&&&&retrofit:与picasso一样都是在okhttp基础之上做的封装,项目中可以直接用了。&&&&AndroidAsync:使用了nio的方式实现的。okhttp没有提供nio的方式,不过nio更适合大量连接的情况,对于移动平台有点杀鸡用牛刀的味道。picasso、uil都不支持inbitmap,项目中有用到picasso的富图片应用需要注意这点。&&&&所以基于上面的对比,我现在还在比较认可volley的。它的代码比较少,即使看完也花不了多少时间,对于移动端网络请求数据量比较少的项目我优先选择它,而且更方便开发者定制化。架构&&&&Volley使用了线程池来作为基础结构,主要分为主线程,cache线程和network线程。主线程和cache线程都只有一个,而NetworkDispatcher线程可以有多个,这样能解决比并行问题。具体可以参考下图,此图节选自Google I/O 演讲。希望大家花点时间理解一下这个图,这个!使用下面是我简单实现Volley的代码:一、Volley单例二、图片加载三、一般Json请求四、Volley Cache使用首先判断是否有网络请求,没有则直接调用缓存数据,有则请求网络数据,保存之。总的来说就是总是使用缓存的数据。导入有两种方式1、Jar导入$ git clone /platform/frameworks/volley$ cd volley$ android update project -p$ ant jar编译好jar之后,直接放在过程libs下面,然后在IDE上按照一般jar的方式导入。2、作为模块导入以android studio为例下载源码:$ git clone /platform/frameworks/volley在android studio2.0上选择File--&New--&New Module然后在app下的build.gradle中加入:compile project(':volley')在项目的settings.gradle文件,使其包含volley:include ':app', ':volley'然后重新build一下整个代码,其中会出现一些Volley编译错误的问题,主要是你下载的Volley 环境设置与你IDE的环境不一致。比如SDK版本,gradle版本等等,你只需改成你IDE版本即可编译通过。下载Volley Android Developer文档:/training/volley/index.htmlVolley主页:/platform/frameworks/volleyVolley仓库:Git&clone&/platform/frameworks/volley亲,需要翻墙哦。。。。。妈妈经常说:好的东西需要分享! 小伙伴们, 你们懂的.Android性能优化(Performance_AQiu) 
 文章为作者独立观点,不代表大不六文章网立场
Performance_AQiu分享android优化相关经验。热门文章最新文章Performance_AQiu分享android优化相关经验。&&&&违法和不良信息举报电话:183-
举报邮箱:
Copyright(C)2016 大不六文章网
京公网安备78Volley框架之一 如何使用,有需要的朋友可以参考下。一直想找个优秀的开源框架学习下,Volley非常合适,研究下来学到了不少知识Volley简介Volley可是说是把AsyncHttpClient和Universal-Image-Loader的优点集于了一身,既可以像AsyncHttpClient一样非常简单地进行HTTP通信,也可以像Universal-Image-Loader一样轻松加载网络上的图片。除了简单易用之外,Volley在性能方面也进行了大幅度的调整,它的设计目标就是非常适合去进行数据量不大,但通信频繁的网络操作,而对于大数据量的网络操作,比如说下载文件等,Volley的表现就会非常糟糕。先解释一下,对于大数据量的网络操作,比如说下载文件等,Volley的表现就会非常糟糕,为什么呢? 因为我们知道对于大文件的下载,我们一般的处理方式是把网络输入流直接写入文件,不写入内存,这样有效防止OOM,但是Volley,并没有针对大文件下载做任何处理,还是通用的实现,先写入内存,然后写入硬盘缓存。导入Volley库Google官方的Volley android studio中添加volley So Volley has been updated to Android studio build style which makes it harder create a jar. But the recommended way for eclipse was using it as a library project and this goes for android studio as well, but when workgin in android studio we call this a module. So here is a guide to how do it the way Google wants us to do it. Guide is based on this nice tutorial.
First get latest volley with git (git clone /platform/frameworks/volley).
In your current project (android studio) click [file] –[Import Module].
Now select the directory where you downloaded Volley to.
Now Android studio might guide you to do the rest but continue guide to verify that everything works correct
Open settings.gradle (find in root) and add (or verify this is included):
include ‘:app’, ‘:volley’
Now go to your build.gradle in your project and add the dependency:
compile project(“:volley”)
Thats all there is to it, much simpler and easier than compiling a jar and safer than relying on third parties jars or maven uploads.另一个经常用的是 mcxiaoke/android-volley 这个非官方的volley项目优化了代码,据说解决了部分官方volley OOM的问题。后面会分析这个项目具体都解决了些什么问题。
compile ‘com.mcxiaoke.volley:library:1.0.19-SNAPSHOT’
或者按照上面的方式,作为库项目添加到AS中
使用这个就不多说了 想粗略的就参考这里吧 《Android Volley完全解析(一),初识Volley的基本用法》 一系列的文章基本用法注意以下地方
mQueue只需要调用一次就行了Volley.newRequestQueue(this);这个方法内部会调用start方法,start方法默认开启1个缓存线程,4个网络请求线程。如果new多次了,那么系统资源肯定最后要被耗尽啊。
mQueue如果能设置为单例的就最好不过了,就不用频繁的去创建销毁线程了,占用系统资源。Volley内部并没有使用线程池来管理缓存线程和网络请求线程。
如果mQueue没有设置为单例模式,那么onDestroy方法必须调用RequestQueue的stop方法,停止缓存线程和网络请求线程。这两个线程内部实现都是while无线循环的,除非调用了stop方法才退出while。想象一下,如果没有stop,那么启动一个activity,如果要做网络请求,那么就new一个RequestQueue,就是创建5个线程出来,但是没有去停止这几个线程,所以一直累积累积,最后后果不堪设想。
public class MainActivity extends AppCompatActivity { private RequestQueue mQ @Override protected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);ButterKnife.bind(this);mQueue = Volley.newRequestQueue(this); } @OnClick(R.id.but) void onClick() {StringRequest stringRequest = new StringRequest("", new Response.Listener&String&() {@Overridepublic void onResponse(String response) {QDLog.d("onResponse:" + response);} }, new Response.ErrorListener() {@Overridepublic void onErrorResponse(VolleyError error) { QDLog.d("onErrorResponse: " + error.getMessage());}});mQueue.add(stringRequest); } @Override protected void onDestroy() {super.onDestroy();mQueue.stop(); }}加载网络图片提供了三种方式 1. ImageRequest ImageRequest继承自Request,所以跟StringRequest等的使用方法差不多,提供了硬盘缓存,同时为了防止OOM对原图片进行了缩放处理。但是另一个问题,ImageRequest不适用于listview,gridview等滑动快速,需要频繁加载图片的场景,因为没有提供内存缓存。这个时候就需要使用ImageLoader咯,相比较ImageRequest,多了内存缓存的功能实现2. ImageLoader 内部还是采用ImageRequest来实现的,只是添加了一级缓存(内存缓存)而已 下面的系列会介绍ImageRequest和ImageLoader的区别和联系3. NetworkImageView 这个就不说了,NetworkImageView是一个自定义View,它是继承自ImageView的,具备ImageView控件的所有功能,并且在原生的基础之上加入了加载网络图片的功能自定义Request必须实现parseNetworkResponse(解析网络请求结果)和deliverResponse(分发结果)这两个方法public class GsonRequest&T& extends Request&T& { private final Listener&T& mL private Gson mG private Class&T& mC public GsonRequest(int method, String url, Class&T& clazz, Listener&T& listener,ErrorListener errorListener) {super(method, url, errorListener);mGson = new Gson();mClass =mListener = } public GsonRequest(String url, Class&T& clazz, Listener&T& listener,ErrorListener errorListener) {this(Method.GET, url, clazz, listener, errorListener); } @Override protected Response&T& parseNetworkResponse(NetworkResponse response) {try {String jsonString = new String(response.data,HttpHeaderParser.parseCharset(response.headers));return Response.success(mGson.fromJson(jsonString, mClass),HttpHeaderParser.parseCacheHeaders(response));} catch (UnsupportedEncodingException e) {return Response.error(new ParseError(e));} } @Override protected void deliverResponse(T response) {mListener.onResponse(response); }}
最新教程周点击榜
微信扫一扫PS一句:最终还是选择CSDN来整理发表这几年的知识点,该文章平行迁移到CSDN。因为CSDN也支持MarkDown语法了,牛逼啊!
【工匠若水&】 阅读前一篇《Google Volley使用之自定义》&
开源项目链接
Volley主页:
Volley仓库:&clone&
Volley GitHub Demo:在GitHub主页搜索Volley会有很多,不过建议阅读&Developer文档。
在Volley使用基础那一篇最后一个知识点说到了Volley的请求,这里再搬过来说说。
在Android Developer上看到的这幅图:
RequestQueue会维护一个缓存调度线程(cache线程)和一个网络调度线程池(net线程),当一个Request被加到队列中的时候,cache线程会把这个请求进行筛选:如果这个请求的内容可以在缓存中找到,cache线程会亲自解析相应内容,并分发到主线程(UI)。如果缓存中没有,这个request就会被加入到另一个NetworkQueue,所有真正准备进行网络通信的request都在这里,第一个可用的net线程会从NetworkQueue中拿出一个request扔向服务器。当响应数据到的时候,这个net线程会解析原始响应数据,写入缓存,并把解析后的结果返回给主线程。
硬着头皮开始吧
直接这么看好空洞,所以直接把clone的工程导入IDE边看代码边看这个图吧。
还是按照前边的顺序分析吧,使用Volley的第一步首先是通过Volley.newRequestQueue(context)得到RequestQueue队列,那么先看下toolbox下的Volley.中的这个方法吧。
* Creates a default instance of the worker pool and calls {@link RequestQueue#start()} on it.
先看如上注释所示,创建一个默认的worker pool,并且调运RequestQueue的start方法。在这个方法里又调运了该类的另一个连个参数的重载方法,如下所示。
* Creates a default instance of the worker pool and calls {@link RequestQueue#start()} on it.
如上所示,该方法有两个参数,第一个Context是为了拿到当前App的Activity的一些信息,第二个参数在默认的RequestQueue newRequestQueue(Context context)方法中传递为null,也就是说在这段代码中的if (stack == null)会被执行。在这个if中对版本号进行了判断,如果版本号大于等于9就使得HttpStack对象的实例为HurlStack,如果小于9则实例为HttpClientStack。至于这里为何进行版本号判断,实际代码中的注释已经说明了。实际上HurlStack类也在toolbox中,他实现了toolbox的HttpStack接口中的HttpResponse performRequest(Request&?& request, Map&String, String& additionalHeaders)方法,其实现过程使用的是HttpURLConnection。而HttpClientStack也在toolbox中,他也实现了toolbox的HttpStack接口的HttpResponse performRequest(Request&?& request, Map&String, String& additionalHeaders)方法,不过其实现过程使用的是HttpClient而已。
其中的userAgent就是App的包名加版本号而已,传入new HttpClientStack(AndroidHttpClient.newInstance(userAgent));作为name TAG使用。
如上HttpStack创建完成之后创建了Network实例。BasicNetwork是Network接口的实现,他们都在toolbox中,BasicNetwork实现了public NetworkResponse performRequest(Request&?& request)方法,其作用是根据传入的HttpStack对象来处理网络请求。紧接着new出一个RequestQueue对象,并调用它的start()方法进行启动,然后将RequestQueue返回。RequestQueue是根目录下的一个类,其作用是一个请求调度队列调度程序的线程池。这样newRequestQueue()的方法就执行结束了。
现在再来看下根目录下RequestQueue队列的start方法,如下所示:
* Starts the dispatchers in this queue.
public void start() {
通过注释可以看出来这里在派发队列的事务。先是创建了一个CacheDispatcher的实例,然后调用了它的start()方法,接着在一个for循环里去创建NetworkDispatcher的实例,并分别调用它们的start()方法。这里的CacheDispatcher和NetworkDispatcher都是继承自Thread的,而默认情况下for循环会执行(DEFAULT_NETWORK_THREAD_POOL_SIZE)四次,也就是说当调用了Volley.newRequestQueue(context)之后,就会有五个线程一直在后台运行,不断等待网络请求的到来,其中一个CacheDispatcher是缓存线程,四个NetworkDispatcher是网络请求线程。
按照之前使用Volley可以知道,得到了RequestQueue之后,我们只需要构建出相应的Request,然后调用RequestQueue的add()方法将Request传入就可以完成网络请求操作了。也就是说add()方法的内部是核心代码了。现在看下RequestQueue的add方法,具体如下:
* Adds a Request to the dispatch queue.
可以看到注释所示,添加一个Request到派发队列。Request是所有请求的基类,是一个抽象类。request.setRequestQueue(this);的作用就是将请求Request关联到当前RequestQueue。然后同步操作将当前Request添加到RequestQueue对象的mCurrentRequests HashSet中做记录。通过request.setSequence(getSequenceNumber());得到当前RequestQueue中请求的个数,然后关联到当前Request。request.addMarker("add-to-queue");添加调试的Debug标记。if (!request.shouldCache())判断当前的请求是否可以缓存,如果不能缓存则直接通过mNetworkQueue.add(request);将这条请求加入网络请求队列,然后返回request;如果可以缓存的话则在通过同步操作将这条请求加入缓存队列。在默认情况下,每条请求都是可以缓存的,当然我们也可以调用Request的setShouldCache(false)方法来改变这一默认行为。OK,那么既然默认每条请求都是可以缓存的(shouldCache返回为true),自然就被添加到了缓存队列中,于是一直在后台等待的缓存线程就要开始运行起来了。现在来看下CacheDispatcher中的run()方法,代码如下所示:
public void run() {
if (DEBUG) VolleyLog.v("start new dispatcher");
Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
首先通过Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);设置线程优先级,然后通过mCache.initialize(); 初始化缓存块,其中mCache是由Volley.java中的newRequestQueue(Context context, HttpStack stack)方法中实例化传入的,其Cache接口的实现为new DiskBasedCache(cacheDir),其中cacheDir默认在Volley.java中不设置为/data/data/app-package/cache/volley/。
接下来由while (true)可以发现缓存线程是一直在执行,其中通过mQuit标记进制是否结束线程的操作。mCacheQueue.take()从阻塞队列获取最前面的一个request,没有request就阻塞等待。接着通过mCache.get(request.getCacheKey());尝试从缓存中取出响应结果,如何为空的话则把这条请求加入到网络请求队列中,如果不为空的话再判断该缓存是否已过期,如果已经过期了则同样把这条请求加入到网络请求队列中,否则就认为不需要重发网络请求,直接使用缓存中的数据即可。在这个过程中调运了parseNetworkResponse()方法来对数据进行解析,再往后就是将解析出来的数据进行回调了。现在先来看下Request抽象基类的这部分代码:
* Subclasses must implement this to parse the raw network response
* and return an appropriate response type. This method will be
* called from a worker thread.
The response will not be delivered
* if you return null.
* @param response Response from the network
* @return The parsed response, or null in the case of an error
abstract protected Response&T& parseNetworkResponse(NetworkResponse response);
通过注释可以看到他就是一个解析模块的功能。
上面说了,当调用了Volley.newRequestQueue(context)之后,就会有五个线程一直在后台运行,不断等待网络请求的到来,其中一个CacheDispatcher是缓存线程,四个NetworkDispatcher是网络请求线程。CacheDispatcher的run方法刚才已经大致分析了,解析来看下NetworkDispatcher中是怎么处理网络请求队列的,具体代码如下所示:
public void run() {
Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
while (true) {
long startTimeMs = SystemClock.elapsedRealtime();
Request&?&
和CacheDispatcher差不多,如上可以看见一个类似的while(true)循环,说明网络请求线程也是在不断运行的。
如上通过mNetwork.performRequest(request);代码来发送网络请求,而Network是一个接口,这里具体的实现之前已经分析是BasicNetwork,所以先看下它的performRequest()方法,如下所示:
NetWork接口的代码:
public interface Network {
* Performs the specified request.
上面说了,就是执行指定的请求。他的BasicNetwork实现子类如下:
public NetworkResponse performRequest(Request&?& request) throws VolleyError {
long requestStart = SystemClock.elapsedRealtime();
while (true) {
HttpResponse httpResponse =
byte[] responseContents =
Map&String, String& responseHeaders = Collections.emptyMap();
这个方法是网络请求的具体实现,也是一个大while循环,其中mHttpStack.performRequest(request, headers);代码中的mHttpStack是Volley的newRequestQueue()方法中创建的实例,前面已经说过,这两个对象的内部实际就是分别使用HttpURLConnection和HttpClient来发送网络请求的,然后把服务器返回的数据组装成一个NetworkResponse对象进行返回。在NetworkDispatcher中收到了NetworkResponse这个返回值后又会调用Request的parseNetworkResponse()方法来解析NetworkResponse中的数据,同时将数据写入到缓存,这个方法的实现是交给Request的子类来完成的,因为不同种类的Request解析的方式也肯定不同。
前面你可以看到在NetWorkDispatcher的run中最后执行了mDelivery.postResponse(request, response);,也就是说在解析完了NetworkResponse中的数据之后,又会调用ExecutorDelivery(ResponseDelivery接口的实现类)的postResponse()方法来回调解析出的数据,具体代码如下所示:
public void postResponse(Request&?& request, Response&?& response, Runnable runnable) {
request.markDelivered();
request.addMarker("post-response");
mResponsePoster.execute(new ResponseDeliveryRunnable(request, response, runnable));
这里可以看见在mResponsePoster的execute()方法中传入了一个ResponseDeliveryRunnable对象,就可以保证该对象中的run()方法就是在主线程当中运行的了,我们看下run()方法中的代码是什么样的:
* A Runnable used for delivering network responses to a listener on the
* main thread.
@SuppressWarnings("rawtypes")
private class ResponseDeliveryRunnable implements Runnable {
private final Request mR
private final Response mR
private final Runnable mR
public ResponseDeliveryRunnable(Request request, Response response, Runnable runnable) {
mRequest =
mResponse =
mRunnable =
@SuppressWarnings("unchecked")
public void run() {
这段代码里的run方法中可以看到如下一部分细节:
// Deliver a normal response or error, depending.
if (mResponse.isSuccess()) {
mRequest.deliverResponse(mResponse.result)
这段代码是最核心的,明显可以看到通过mRequest的deliverResponse或者deliverError将反馈发送到回调到UI线程。这也是你重写实现的接口方法。
再来整体看下
现在是该回过头去看背景知识模块了,再看下那幅官方图,对比就明白咋回事了。结合上图和如上分析可以知道:
当一个RequestQueue被成功申请后会开启一个CacheDispatcher和4个默认的NetworkDispatcher。
CacheDispatcher缓存调度器最为第一层缓冲,开始工作后阻塞的从缓存序列mCacheQueue中取得请求;对于已经取消的请求,标记为跳过并结束这个请求;新的或者过期的请求,直接放入mNetworkQueue中由N个NetworkDispatcher进行处理;已获得缓存信息(网络应答)却没有过期的请求,由Request的parseNetworkResponse进行解析,从而确定此应答是否成功。然后将请求和应答交由Delivery分发者进行处理,如果需要更新缓存那么该请求还会被放入mNetworkQueue中。
将请求Request add到RequestQueue后对于不需要缓存的请求(需要额外设置,默认是需要缓存)直接丢入mNetworkQueue交给N个NetworkDispatcher处理;对于需要缓存的,新的请求加到mCacheQueue中给CacheDispatcher处理;需要缓存,但是缓存列表中已经存在了相同URL的请求,放在mWaitingQueue中做暂时处理,等待之前请求完毕后,再重新添加到mCacheQueue中。
网络请求调度器NetworkDispatcher作为网络请求真实发生的地方,对消息交给BasicNetwork进行处理,同样的,请求和结果都交由Delivery分发者进行处理。
Delivery分发者实际上已经是对网络请求处理的最后一层了,在Delivery对请求处理之前,Request已经对网络应答进行过解析,此时应答成功与否已经设定;而后Delivery根据请求所获得的应答情况做不同处理;若应答成功,则触发deliverResponse方法,最终会触发开发者为Request设定的Listener;若应答失败,则触发deliverError方法,最终会触发开发者为Request设定的ErrorListener;处理完后,一个Request的生命周期就结束了,Delivery会调用Request的finish操作,将其从mRequestQueue中移除,与此同时,如果等待列表中存在相同URL的请求,则会将剩余的层级请求全部丢入mCacheQueue交由CacheDispatcher进行处理。
至此所有搞定。
PPPS一句:通过上面原理分析之后总结发现,推荐整个App全局持有一个RequestQueue的做法,这样会有相对比较高的性能效率。
阅读(...) 评论()

我要回帖

更多关于 volley框架详解 的文章

 

随机推荐