Volley框架剖析( 二)从开始到结束

上一篇中,我们分析了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的很多细节还是很值得我们学习。下一次我们对一些重要的类进行分析。

时间: 2024-11-05 04:59:10

Volley框架剖析( 二)从开始到结束的相关文章

volley 框架剖析(一) 面向接口的编程

Volley是Google出品的一个轻量级的网络框架,默认实现,主要用于小数据量的网络请求.这里就按从粗到细,自上而下的过程,给大家剖析这个牛X的框架. 这个框架的代码量虽少,但却把面向接口的编程这个原则发挥的淋漓尽致.这个框架是怎么构成的呢? 先看包的结构. 有com.android.volley 及 com.android.volley.toolbox两个包. 其中com.android.volley中的接口和类,是基础框架,构成了一个基于队列的网络请求功能. 而com.android.vo

volley 框架剖析(三) Request类精解

Request是所有网络请求的基类,它实现了Comparable接口,前面提到RequestQueue可按照优先级队进行排序,这里的Comparable就是为优先级排序作准备. 接下来,我们对Request中比较重要或有趣的成员或方法进行一一解释. Request中包括一个对支持的Http方法的定义.这里使用的内部接口而不是枚举来实现的. public interface Method { int DEPRECATED_GET_OR_POST = -1; int GET = 0; int POS

volley 框架剖析(四) 之HTTPCache设计

记得有位高人说过,成功在于细节.同样,一份代码质量如何,同样也在于对细节的处理上.考虑的情况越多,则出现问题的概率也就越低. Cache之前也写过,但看了Volley的Cache之后,真心觉得差距大了.不废话了,还是上大餐吧 public static class Entry { /** The data returned from cache. */ public byte[] data; /** ETag for cache coherency. */ public String etag;

Volley框架源码浅析(二)

尊重原创 http://write.blog.csdn.net/postedit/25921795 在前面的一片文章Volley框架浅析(一)中我们知道在RequestQueue这个类中,有两个队列:本地队列和网络队列 /** The cache triage queue. */ private final PriorityBlockingQueue<Request<?>> mCacheQueue = new PriorityBlockingQueue<Request<

Volley框架的原理剖析--&gt;

Volley的主要特点: 1.扩展性强.Volley中大多数都是基于接口的设计,可配置性强. 2.一定程度符合Http规范,包括返回ResponseCode的处理,请求头的处理,缓存机制的支持等.并支持重试及优先级定义. 3.默认Android2.3及以上基于HttpURLConnection,2.3以下基于HttpCllient. 4.提供简便的图片加载工具. Volley主要是通过两种Dispatch Thread不断从RequestQueue中取出请求,根据是否已缓存调用Cache或Net

Android网络通信Volley框架源代码浅析(二)

尊重原创 http://write.blog.csdn.net/postedit/25921795 在前面的一片文章Volley框架浅析(一)中我们知道在RequestQueue这个类中,有两个队列:本地队列和网络队列 /** The cache triage queue. */ private final PriorityBlockingQueue<Request<?>> mCacheQueue = new PriorityBlockingQueue<Request<

Android Volley框架的使用(二)

使用请求队列RequestQueue Volley中的Request都需要添加到RequestQueue中才能执行,所以首先需要创建一个RequestQueue RequestQueue = Volley.newRequestQueue(mContext); 通常情况在一个应用中需要统一管理一个请求队列,所以采用单例模式(注意:这不是必须的),创建一个类并在这个类中初始化RequestQueue等核心对象,以及实现一些我们所需的方法: 代码如下: package com.javen.volley

Volley框架

Volley框架 volley是谷歌官方在2013年推出的Android平台上的网络通信库 特点 网络通信更快,更简单,开发效率高,稳定性高. 对get和post网络请求以及网络图片高效的异步处理请求. 可以对网络请求进行优先级排序处理. 网络请求的缓存. 多级别取消请求. 和Activity生命周期的联动. 缺点不适合数据的上传与下载 Get和Post请求接口的使用请求对象 StringRequest 返回结果类型不确定(它包含后面两种) StringRequest request = new

Android之Volley框架源码分析

临近毕业,各种事情各种忙.我也没有认真专注写过博客,最近仔细看了Volley框架的使用及其源码,思前想后,想挑战一下自己,还是写一篇博客来分享,如有错误,欢迎吐槽. Volley简介 网络请求是一个App很重要的一部分,android系统只是提供了一个平台,而android应用则是基于这个平台上进行展示数据,起到与用户进行交互的作用,数据来源于服务端,而二者之间必须通过互联网进行传输数据,在Android系统发布初期,很多开发者都是在Apache协会的Http协议的基础上进行网络请求方法的封装,