Android:Volley源码解析
来源:互联网 发布:怎么联系淘宝直播达人 编辑:程序博客网 时间:2024/06/06 01:05
简单实例
Volley是一个封装HttpUrlConnection和HttpClient的网络通信框架,集AsyncHttpClient和Universal-Image-Loader的优点于了一身,既可以像AsyncHttpClient一样非常简单地进行HTTP通信,也可以像Universal-Image-Loader一样轻松加载并缓存下载的图片。Volley在性能方面也进行了大幅度的调整,它的设计目标就是进行数据量不大,但通信频繁的网络操作
,而对于大数据量的网络操作,比如说下载文件等,Volley的表现就会比较糟糕。从下面这个简单的实例来研究一下源码。
RequestQueue mQueue = Volley.newRequestQueue(MainActivity.this);StringRequest stringRequest = new StringRequest("http://www.baidu.com", new Response.Listener<String>() { @Override public void onResponse(String s) { tv.setText(s); }}, new Response.ErrorListener() { @Override public void onErrorResponse(VolleyError volleyError) { }});mQueue.add(stringRequest);
流程
1、以静态工厂形式实例化一个RequestQueue对象
RequestQueue mQueue = Volley.newRequestQueue(MainActivity.this);
- 首先看一下RequestQueue这个类:
public class RequestQueue { private AtomicInteger mSequenceGenerator; private final Map<String, Queue<Request>> mWaitingRequests; private final Set<Request> mCurrentRequests; private final PriorityBlockingQueue<Request> mCacheQueue; private final PriorityBlockingQueue<Request> mNetworkQueue; private static final int DEFAULT_NETWORK_THREAD_POOL_SIZE = 4; private final Cache mCache; private final Network mNetwork; private final ResponseDelivery mDelivery; private NetworkDispatcher[] mDispatchers; private CacheDispatcher mCacheDispatcher; public RequestQueue(Cache cache, Network network, int threadPoolSize, ResponseDelivery delivery) { this.mSequenceGenerator = new AtomicInteger(); this.mWaitingRequests = new HashMap(); this.mCurrentRequests = new HashSet(); this.mCacheQueue = new PriorityBlockingQueue(); this.mNetworkQueue = new PriorityBlockingQueue(); this.mCache = cache; this.mNetwork = network; this.mDispatchers = new NetworkDispatcher[threadPoolSize]; this.mDelivery = delivery; } public RequestQueue(Cache cache, Network network, int threadPoolSize) { this(cache, network, threadPoolSize, new ExecutorDelivery(new Handler(Looper.getMainLooper()))); } public RequestQueue(Cache cache, Network network) { this(cache, network, 4); } ...}
从构造函数可知,mWaitingRequests、mCurrentRequests、mCacheQueue、mNetworkQueue是以组合形式实例化,后两者是阻塞队列;而mCache、mNetwork是以聚合形式注入;mDelivery默认也是组合形式new ExecutorDelivery(new Handler(Looper.getMainLooper())))
实例化。
- newRequestQueue方法:
public static RequestQueue newRequestQueue(Context context) { return newRequestQueue(context, (HttpStack)null); }
public static RequestQueue newRequestQueue(Context context, HttpStack stack) { File cacheDir = new File(context.getCacheDir(), "volley"); String userAgent = "volley/0"; try { String network = context.getPackageName(); PackageInfo queue = context.getPackageManager().getPackageInfo(network, 0); userAgent = network + "/" + queue.versionCode; } catch (NameNotFoundException var6) { ; } if(stack == null) { if(VERSION.SDK_INT >= 9) { stack = new HurlStack(); } else { stack = new HttpClientStack(AndroidHttpClient.newInstance(userAgent)); } } BasicNetwork network1 = new BasicNetwork((HttpStack)stack); RequestQueue queue1 = new RequestQueue(new DiskBasedCache(cacheDir), network1); queue1.start(); return queue1; }
结合RequestQueue类可知,实例化的RequestQueue对象,注入了new DiskBasedCache(cacheDir)
和network1
,缓存方式默认是磁盘缓存,NetWork对象会根据系统版本,选用不同的Http通信方式。
- queue.start()方法
public void start() { this.stop(); this.mCacheDispatcher = new CacheDispatcher(this.mCacheQueue, this.mNetworkQueue, this.mCache, this.mDelivery); this.mCacheDispatcher.start(); for(int i = 0; i < this.mDispatchers.length; ++i) { NetworkDispatcher networkDispatcher = new NetworkDispatcher(this.mNetworkQueue, this.mNetwork, this.mCache, this.mDelivery); this.mDispatchers[i] = networkDispatcher; networkDispatcher.start(); } }
CacheDispatcher和NetworkDispatcher都是继承Thread类,所以这个方法生成一条缓存分发线程,和四条网络线程。
- CacheDispatcher类继承Thread类,所有参数都是聚合形式注入,看下关键的run()方法,由于代码较长,这里不贴了,分段分析下几个比较重要的方法
while(true){ ... Request e = (Request)this.mCacheQueue.take(); ...}
首先任务是一个死循环,由于mCacheQueue是个阻塞队列,所以将不断地从阻塞队列读取Request
Entry entry = this.mCache.get(e.getCacheKey()); if(entry == null) { e.addMarker("cache-miss"); this.mNetworkQueue.put(e); } else if(entry.isExpired()) { e.addMarker("cache-hit-expired"); e.setCacheEntry(entry); this.mNetworkQueue.put(e); } else { e.addMarker("cache-hit"); Response response = e.parseNetworkResponse(new NetworkResponse(entry.data, entry.responseHeaders)); ... }
判断请求是否有缓存,如果没有或者缓存已经过期,将请求放到网络队列里面
。否则找到缓存,则进行下面的操作。
Response response = e.parseNetworkResponse(new NetworkResponse(entry.data, entry.responseHeaders));
parseNetworkResponse是Request类的抽象方法,我们进去StringRequest看下:
protected Response<String> parseNetworkResponse(NetworkResponse response) { String parsed; try { parsed = new String(response.data, HttpHeaderParser.parseCharset(response.headers)); } catch (UnsupportedEncodingException var4) { parsed = new String(response.data); } return Response.success(parsed, HttpHeaderParser.parseCacheHeaders(response)); }
可看作是对网络下载的数据进行解析处理,然后返回。
this.mDelivery.postResponse(e, response);
最后进行这一步,mDelivery是在RequestQueue里面实例化后注入CacheDispatcher的,具体的实例化对象:new ExecutorDelivery(new Handler(Looper.getMainLooper()))。看下ExecutorDelivery类,找到postResponse方法。
public void postResponse(Request<?> request, Response<?> response) { this.postResponse(request, response, (Runnable)null); } public void postResponse(Request<?> request, Response<?> response, Runnable runnable) { ... this.mResponsePoster.execute(new ExecutorDelivery.ResponseDeliveryRunnable(request, response, runnable)); }
继续往下看
private class ResponseDeliveryRunnable implements Runnable { ... run(){ ... if(this.mResponse.isSuccess()) { this.mRequest.deliverResponse(this.mResponse.result); } ... } ...}
deliverResponse方法同样是Request类的抽象方法,我们进去StringRequest看下
protected void deliverResponse(String response) { this.mListener.onResponse(response); }
就一句回调
- NetworkDispatcher类同样继承Thread类,其分析过程和CacheDispatcher差不多,重要的同样是以下几步:
1、从网络阻塞队列读取请求,request = (Request)this.mQueue.take();
2、网络下载,NetworkResponse e = this.mNetwork.performRequest(request);(如果是CacheDispatcher这一步就是缓存判断)
3、处理下载后的数据,Response response = request.parseNetworkResponse(e);
3、对处理后的数据进行回调,this.mDelivery.postResponse(e, response)。
2、实例化一个Request对象
StringRequest stringRequest = new StringRequest (url,listener,errorListener);
public class StringRequest extends Request<String> { private final Listener<String> mListener; public StringRequest(int method, String url, Listener<String> listener, ErrorListener errorListener) { super(method, url, errorListener); this.mListener = listener; } public StringRequest(String url, Listener<String> listener, ErrorListener errorListener) { this(0, url, listener, errorListener); } protected void deliverResponse(String response) { this.mListener.onResponse(response); } protected Response<String> parseNetworkResponse(NetworkResponse response) { String parsed; try { parsed = new String(response.data, HttpHeaderParser.parseCharset(response.headers)); } catch (UnsupportedEncodingException var4) { parsed = new String(response.data); } return Response.success(parsed, HttpHeaderParser.parseCacheHeaders(response)); }}
由第一个分析步骤可以知道,这个Request主要就是进行两个操作,也就是重写两个方法。
protected abstract Response<T> parseNetworkResponse(NetworkResponse var1);
对下载后的数据进行解析处理;protected abstract void deliverResponse(T var1);
最后回调操作这个数据的方法。
所以构造函数仅需下载地址和回调操作的方法。
3、调用queue.add()方法
if(!request.shouldCache()) { this.mNetworkQueue.add(request); return request; }
如果不需要缓存就直接添加到网络队列里面,Request有个比较重要的布尔字段mShouldCache,默认是用来判断是否要进行磁盘缓存的。
this.mCacheQueue.add(request);
否则将其添加到缓存队列,这个方法上面也会进行一些当前队列和等待队列的防重复的操作。
小结
框架部分:
1、实例化一个RequestQueue对象,开启一条缓存线程和默认的四条网络线程,线程不断地从缓存阻塞队列和网络阻塞队列里面读取请求;
2、如果缓存线程从缓存队列里面读取的请求已经缓存过,则解析数据回调操作方法,否则将其添加到网络队列;
3、如果缓存线程从缓存队列里面读取的请求没有缓存过,则添加到网络队列。
4、网络线程从网络阻塞队列不断读取请求,读到请求后则由封装好的HttpStack对象进行网络下载处理、下载后回调对数据处理的方法,处理后回调操作数据的方法。
客户部分:
1、实例化一个请求对象,在请求对象里面重写处理网络下载后的数据的方法,和操作处理后的数据的方法。
2、将请求对象添加到请求队列,请求需要缓存则会被添加到分配到缓存队列,不需要则被添加到网络队列。
之前看过一个问题,说框架和库有什么不同,高人答曰:框架是他调用你代码,库是你调用他代码。优秀的框架拓展性是如此之强,虽然自己远没那个能力,不过也算开了眼界!
- Android Volley 源码解析
- Android:Volley源码解析
- Android Volley源码解析
- Android Volley 源码解析
- Android Volley源码解析
- Volley学习(一)Android Volley源码解析
- Android--Volley(四)--源码解析
- Android之Volley 源码解析
- Android Volley核心源码解析
- Android Volley核心源码解析
- android Volley源码解析笔记
- Android Volley框架源码解析
- 【Volley】Volley源码解析
- android中volley框架源码解析
- Android Volley 图片加载相关源码解析
- Android 网络框架 Volley 源码解析
- android volley封装及源码解析
- Android开发——Volley源码解析
- Linux内核RCU(Read Copy Update)锁简析
- android 定位
- POJ 1201 & HDU1384 & ZOJ 1508 Intervals(差分约束+spfa 求最长路径)
- 判断两个时间是不是同一天
- E-JSON数据传输标准
- Android:Volley源码解析
- 黑马程序员——Java String类 and 正则表达式(第七篇)
- POJ 3100 && HDU 2740 Root of the Problem(水~)
- nltk在python中的安装,以及nltk的data库
- HBase使用常见异常
- HDU5280 Senior's Array(简单DP)
- Spring web flow——披萨订购流程示例(1)
- LightOJ 1215 Finding LCM(数论)
- NAO机器人中xx.cpp文件运行遇到问题及其解决办法