【进阶android】Volley源码分析——Volley的流程

来源:互联网 发布:微信破解密码软件 编辑:程序博客网 时间:2024/06/05 09:11

    本文章开始分析Volley的具体源代码了;首先介绍Volley的总体流程,文章总体分为三个部分:Request类的分析、RequestQueen类的分析以及Volley的总体流程。

一、Request类

        Volley框架之中,Request是对一次网络请求流程的抽象;从发起请求、获取响应、解析响应、传递响应都属于Request的范畴之中。

       而Request类中一共有16个的属性,一个接口,一个枚举;可以将其分为以下三类:

        1、用于描述Request自身状态的属性;主要为以下几个属性:


2、用以描述请求的属性:


        3、响应相关的属性:
         剩下的5个属性之中,有4个属性是和日志(logcat)相关的,余下的一个属性较为重要,其类别为RequestQueue,引用了一个RequestQueue对象。我们将在后面详细介绍该类。

         至此,我们便介绍完Request类中主要的属性;其中需要补充说明的是Response类中除了有一个错误监听器之外(ErrorListener),还有一个普通的正常监听器(Listener)该监听器为一个正常解析了响应的回调接口。Request类中并没有该正常监听器的引用,这是因为Request类是一个抽象类,它将这一部分的工作下放给它的子类了。

       最后对于Cache.Entry这个属性做一个说明,Cache是一个接口,是对整个Volley中的内存缓存机制做了一个抽象;Volley中的内存缓存默认是一个集合,Cache接口主要抽象了对这个集合的操作,例如初始化、增加缓存、获取缓存等等,而Cache.Entry就是内存缓存之中的一个元素(实体),具体将在【进阶android】Volley源码分析——Volley的缓存这篇文章之中分析。

        Request类中有两个方法较为重要,一个是parseNetworkResponse方法;一个是deliverResponse方法;这两个方法都是抽象方法,需要其子类进行个性化重写,parseNetworkResponse方法主要是将HTTP响应解析生成一个Response<T>对象;deliverResponse方法则主要是由主线程调用,负责主线程对响应的处理。

    至此,Request的主要属性和方法则介绍完成;上文曾提过,一个Request对象是一次网络请求流程的抽象;当要进行一次网络请求时,首先需要知道请求的URL,根据URL构造一个Request对象,接着会结合一个RequestQueue对象进行一次网络请求,网络请求成功,则将响应通过Request对象的parseNetworkResponse方法生成一个Response对象,然后再讲Request及其对应的Response封装为一个消息,传递给主线程,主线程调用Request对象的deliverResponse方法来执行对响应的处理,例如根据响应结果更新UI等等。其中构造一个Request对象、调用deliverResponse方法等是在主线程之中执行的;网络请求,解析Response等操作则是在网络线程之中执行的。

    这就是整个Volley中一次网络请求的总体流程。由此可以看出Volley对网络请求中的具体功能(HTTP如何通信)几乎未做相关优化,只是把网络请求之前和网络请求之后的工作进行了相应的优化,使之更加适用于Android模式,例如网络线程与主线程的通信皆是采用的Handler机制。当然,真正的Volley框架还会在这个基础流程之上加入缓存机制。

    下面我们看看RequestQueue类。

二、RequestQueue类

    做过Android开发的程序员应该都知道,Android的UI线程即主线程,并不允许进行网络请求的操作(会报出一个NetworkOnMainThreadException异常),因为网络请求本身就是一个耗时的操作,要进行网络请求,一个较好的方法则是使用子线程。基于此,Volley大部分的工作并非在主线程上完成的,对于主线程它只是提供了响应的一些接口来执行,例如Response类中的ErrorListener接口和Listener接口皆是Volley提供给主线程处理的接口,这两个接口一个是处理请求失败的情况,一个是处理请求成功的情况。

    默认情况下,Volley会除主线程外,开启5个子线程(主线程并不是Volley开启的,这是一个常识),5个子线程中有4个网络线程,主要处理网络请求,一个缓存线程,主要处理缓存请求。而对这5个线程的管理则交由RequestQueue负责了。

    总体而言,RequestQueue有两个主要的功能,一个功能就如它的名字,用来管理Request的队列;另一个功能则是用来开启、停止这五个子线程。

    RequestQueue主要有9个比较重要的属性分别如下:

      以上便是对RequestQueue属性的大致分析;而在RequestQueue方法之中,本章主要分析start()方法和add(Request request)方法;因为对于整个Volley框架而言,这两个方法对整个框架的流程而言,都至关重要。

      两个方法的逻辑并不复杂,但是Volley框架的运行离不开这两个方法;两个方法都是由主线程调用,其中start方法主要开启RequestQueue对应的5个线程,及初始化4个NetworkDispatcher对象及1个CacheDispatcher对象,这5个对象都是Thread对象的子对象,5个子线程对应的处理逻辑我们将在【进阶android】Volley源码分析——Volley的线程一文中详细分析。

    start()方法的主要代码如下:
<pre name="code" class="java">public void start() {        // Make sure any currently running dispatchers are stopped.        //确保当前所有运行的子线程线程都要被停止        stop();        // Create the cache dispatcher and start it.        //创建一个缓存调度器,并运行其对应的线程        mCacheDispatcher = new CacheDispatcher(mCacheQueue, mNetworkQueue, mCache, mDelivery);        mCacheDispatcher.start();        // Create network dispatchers (and corresponding threads) up to the pool size.        //创建制定个数的网络调度器,运行相应的子线程        for (int i = 0; i < mDispatchers.length; i++) {            NetworkDispatcher networkDispatcher = new NetworkDispatcher(mNetworkQueue, mNetwork,                    mCache, mDelivery);            mDispatchers[i] = networkDispatcher;            networkDispatcher.start();        }    }


    下面我们继续分析RequestQueue的add(Request request)方法;顾名思义,该方法是将Request添加到请求队列之中,在此之上要根据Request的属性判断需要添加到那些队列之中(从上文RequestQueue的属性可以看出,RequestQueue拥有不同的Request集合)。
   该方法代码如下:
   
public Request add(Request request) {        // Tag the request as belonging to this queue and add it to the set of current requests.        request.setRequestQueue(this);//将该RequestQueue对象映射到Request对象之中        synchronized (mCurrentRequests) {            mCurrentRequests.add(request);//添加到总队列之中        }        // Process requests in the order they are added.        request.setSequence(getSequenceNumber());//生成请求唯一码        request.addMarker("add-to-queue");        // If the request is uncacheable, skip the cache queue and go straight to the network.        if (!request.shouldCache()) {//如果该请求不用缓存,则添加到需要网络线程处理的列表之中,并返回            mNetworkQueue.add(request);            return request;        }        // Insert request into stage if there's already a request with the same cache key in flight.        synchronized (mWaitingRequests) {            String cacheKey = request.getCacheKey();//Request的缓存key就是该Request对象对应的URL            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);//如果不存在则直接将该Request对象添加缓存线程处理的队列之中            }            return request;        }    }
    根据以上代码,我们可以分析出add方法的流程如下:
    1、将该RequestQueue对象映射到入参对应的Request对象之中;
    2、将入参对应的Request对象添加到总队列之中(mCurrentRequests);
    3、如果入参对应的Request对象不需要缓存(根据Request对应的mShouldCache属性),直接添加到需要网络线程处理的队列之中(mNetWorkQueue),并直接退出方法;这一类别(mShouldCache为false)的Request对象根本不用考虑缓存,直接进行网络请求。
    4、如果入参需要缓存,则判断该入参对应的Request对象是否有重复URL的、正处于请求之中的Request对象,如果有,则将其加入等待队列之中(mWaitingRequests)进行等待,而无需进入缓存队列之中;
    5、如果入参需要缓存且不存在重复的Request,则将入参对应的Request对象添加到需要缓存线程处理的队列之中。
    一般来说,Volley中的Request对象都是需要缓存的(当然也可设置为不需要缓存),因此,add方法一般会走上面的1、2、4、5这四个步骤。也就是说,调用add方法添加的Request对象,一般会将其添加到总队列(mCurrentRequests)和需要缓存线程处理的队列两个队列之中(至于重复请求的情况,相对而言较少)。
   至此,我们就大致分析了RequestQuene的源代码。
   下面,我们继续分析Volley的总体流程。
三、Volley的总体流程
   关于Volley的总体流程,网上有一张图片,可以很好的对其进行概括,如下所示:
    通过这幅流程图,在结合上文所述的(尤其是RequestQueue的add方法分析)应该能够看懂这幅流程图所描述的意思。
    总体而言,这幅图主要讲的是需要缓存的Request对象的流程(不需要缓存的Request对象其实在该图之中也有完整的描述,读者可以自行分析)。
   对于一个需要缓存的Request对象,被添加到缓存队列之后;缓存线程从同一个缓存队列之中获取需要处理的Request对象;如果该Request对象对应的URL存在缓存,则无需网络请求,直接从缓存之中读取、解析上一次缓存的HTTP响应数据,将解析成功的Response<T>对象直接传递给主线程即可;如果Request对象对应的URL不存在缓存,则表示从来没有对此URL进行过网络请求,这种情况下,该Request请求则一定要添加到需要网络线程处理的队列之中,网络线程从该队列之中获取到一个Request对象后,就会通过该对象执行一次HTTP请求,随即解析原始HTTP响应,将其转为一个Response<T>对象,同时将原始HTTP响应写入缓存之中,最后与缓存的流程一致将Response<T>对象传递给主线程处理即可。
   至此,整个Volley的总体流程我们便简单的分析了一遍;通过本文的撰写,我对Volley的总体流程、以及Request、RequestQueue有了一个大致的认知与了解!当然,由于本人自身水平所限,文章肯定有一些不对的地方,希望大家指出!
    希望大家能一起进步,谢谢!
   

1 0
原创粉丝点击