Volley框架剖析( 二)从开始到结束
来源:互联网 发布:网络在线咨询图片 编辑:程序博客网 时间:2024/05/22 14:32
上一篇中,我们分析了Volley的一个总体组成。今天我们继续分析Volley的一个数据流走向,即从初始化到发起请求,再到请求结束的一个流程。
先看初始化。
Volley的初始化,实际上就是返回一个RequestQueue的队列。在Volley中调用。一个最简单的创建方式即有一个Context即可。
/** * Creates a default instance of the worker pool and calls {@link RequestQueue#start()} on it. * * @param context A {@link Context} to use for creating the cache dir. * @return A started {@link RequestQueue} instance. */ public static RequestQueue newRequestQueue(Context context) { return newRequestQueue(context, null); }
我们的分析当然不是点到即止,所以,我们重点关注参数最全的构造函数。
/** * Creates a default instance of the worker pool and calls {@link RequestQueue#start()} on it. * You may set a maximum size of the disk cache in bytes. * * @param context A {@link Context} to use for creating the cache dir. * @param stack An {@link HttpStack} to use for the network, or null for default. * @param maxDiskCacheBytes the maximum size of the disk cache, in bytes. Use -1 for default size. * @return A started {@link RequestQueue} instance. */ public static RequestQueue newRequestQueue(Context context, HttpStack stack, int maxDiskCacheBytes) { File cacheDir = new File(context.getCacheDir(), DEFAULT_CACHE_DIR); String userAgent = "volley/0"; try { String packageName = context.getPackageName(); PackageInfo info = context.getPackageManager().getPackageInfo(packageName, 0); userAgent = packageName + "/" + info.versionCode; } catch (NameNotFoundException e) { } if (stack == null) { if (Build.VERSION.SDK_INT >= 9) { stack = new HurlStack(); } else { // Prior to Gingerbread, HttpUrlConnection was unreliable. // See: http://android-developers.blogspot.com/2011/09/androids-http-clients.html stack = new HttpClientStack(AndroidHttpClient.newInstance(userAgent)); } } Network network = new BasicNetwork(stack); RequestQueue queue; if (maxDiskCacheBytes <= -1) { // No maximum size specified queue = new RequestQueue(new DiskBasedCache(cacheDir), network); } else { // Disk cache size specified queue = new RequestQueue(new DiskBasedCache(cacheDir, maxDiskCacheBytes), network); } queue.start(); return queue; }
这个方法有三个参数Context,HttpStack和maxDiskCacheBytes.
前面说了HttpStack是一个接口,用于Http请求的具体实现,maxDiskCacheBytes用于创建磁盘缓存时来设置最大的缓存容量。
初始化中有意思的是自定义了一个USERAGENT,这个USERAGENT用在HTTP头部中,表示当前的请求是由当前软件发起,方便日后查找问题和统计。这里也建议自己在创建网络请求的时候,用自己的UA代替。按照经验,UA通常由软件(框架)名称+版本+其他附加信息构成。
创建HTTP请求这里也区别开了SDK VERSION 在9以上和9以下。
对于9以上的版本,直接使用了HttpURLConnection
,对于9以下的版本使用了AndroidHttpClient
,什么原因呢,可以参考:http://android-developers.blogspot.com/2011/09/androids-http-clients.html
由于这文章需要翻墙,我这里把要点罗列如下:
1.
HttpURLConnection
是一个轻量级的Http连接方案,适用于大多数应用,它支持流压缩与网络缓存,能够减少网络流量与节省电池,
因此推荐Gingerbread 及以上的使用这个API。
2. 在Gingerbread以下,HttpURLConnection
当在一个还没有读完的流上调用close方法时,这个流上没有读完的部分会缓存下来,然后会加到下一个请求的数据区,导致下一个请求的数据错误。
3.AndroidHttpClient
复杂扩展性好且稳定,但AndroidTeam很难在保证兼容性的同时改进一些特性,因此,通常不推荐使用。
当然如果你是自己扩展之后,传的一个实现了HttpStack的对象,就不会走到上面的逻辑中。
在根据版本获取了HttpStack对象后,将其作为参数传给Network的默认实现BasicNetwork对象。即BasicNetwork中实际上是对HttpStack的一个包装(当然,如果自己实现了其他的Network,就不一定需要这个HttpStack)。
之后,根据maxDiskCacheBytes创建了一个磁盘缓存。
最后,启动这个RequestQueue。
启动时做了两件事,创建CacheDispatcher和NetworkDispatcher。这两个都是线程类的子类,CacheDispatcher 的线程主要在作用是本地的IO操作,加载缓存用。NetworkDispatcher的线程主要执行网络操作,默认创建了1个缓存线程和4个网络线程。
在初始化完成之后,就可以使用RequestQueue来发起网络请求。
发起请求从RequestQueue的add方法开始。
http://img.blog.csdn.net/20150425163836789
流程如上图,是比如简单的。这里说几个有趣细节。
在add的第一行代码,我们看到 request把RequestQueue传到了对象中,并作为一个成员变量保存。那为什么?因为request的生命周期是由request的一些方法来维护,此后就与这个queue无关了,但是在一个request又需要在结束时,把自己从queue中移除掉,它需要 这个引用来做移除操作。可以参见request.finish的代码。
if (mRequestQueue != null) { mRequestQueue.finish(this); }
每个请求,有一个唯一的序列号,这个是用AtomicInteger来实现的。
private AtomicInteger mSequenceGenerator = new AtomicInteger(); /** * Gets a sequence number. */ public int getSequenceNumber() { return mSequenceGenerator.incrementAndGet(); }
在没有主动设置优先级的情况,这个是做为request的优先级来处理的。即数字越小,优先级越高。
还有个有意思的点是request的日志系统,所有的状态改变,都会有事件记录,以便跟踪问题。
从上图可以看出,比如缓存命中情况,网络请求情况,重试情况等,都有一一记录。
volley避免重复请求节约网络资源的逻辑写得很有技巧。这里巧妙的利用了一个空的value来处理,可以少生成一个链表对象。
// Insert request into stage if there's already a request with the same cache key in flight. synchronized (mWaitingRequests) { String cacheKey = request.getCacheKey(); if (mWaitingRequests.containsKey(cacheKey)) { // There is already a request in flight. Queue up. Queue<Request<?>> stagedRequests = mWaitingRequests.get(cacheKey); if (stagedRequests == null) { stagedRequests = new LinkedList<Request<?>>(); } stagedRequests.add(request); mWaitingRequests.put(cacheKey, stagedRequests); if (VolleyLog.DEBUG) { VolleyLog.v("Request for cacheKey=%s is in flight, putting on hold.", cacheKey); } } else { // Insert 'null' queue for this cacheKey, indicating there is now a request in // flight. mWaitingRequests.put(cacheKey, null); mCacheQueue.add(request); }
如果是第一次请求,直接放入一个空value,第二次如果是相同的请求,才会增加一个链表来缓存相同的request。当第一个请求网络完成后,它才会把这个链表中的请求通通加到缓存队列中。这样,即可以保证即时很短时间内的并发相同请求,实际只有一个才会使用网络资源,又能保证相同的请求不会被丢弃。
volley的很多细节还是很值得我们学习。下一次我们对一些重要的类进行分析。
- Volley框架剖析( 二)从开始到结束
- 从开始到结束
- Android中关于Volley的使用(二)从RequestQueue开始来深入认识Volley
- 爱 从哪里开始 到哪里结束
- iOS应用开发 - 从开始到结束
- 一个项目从开始到结束-1
- volley 框架剖析(三) Request类精解
- Volley框架解读(二)
- 2. OpCode,从哪里开始,到哪里结束
- 从现在开始到考试结束不冲浪啦
- 计算从开始日期到结束日期经过的天数
- 记录WebView从开始加载到渲染结束的时间
- 结束到开始之间
- 网络基础技术:从HttpURLConnection到Volley框架
- Android网络框架总结Volley(二)
- Android Volley框架的使用(二)
- 浅谈Volley网络框架(二)
- Android Volley框架的使用(二)
- 阿里巴巴前端面试题:三列布局知多少?
- Visual Studio 2013 编写汇编代码
- COM和DLL的一些区别
- LAMP环境的搭建及注意点
- 面试常见问题知识点汇总(干货)
- Volley框架剖析( 二)从开始到结束
- linux系统中如何查看日志 (常用命令)
- 使用正则表达式校验微信号
- 将数组a中n个元素按相反顺序存放
- TCP/IP
- 机房收费系统重构(2)——未声明“ConfigurationManager”
- 编程之美15-彩色的树
- Linux-(10)Linux中的用户和组
- Hibernate中session的clear(),flush(),evict()方法详解