Android Volley框架源码详细解析

Part 1.从RequestQueue说起

Volley框架的使用

Volley是Google官方出的一套小而巧的异步请求库,该框架封装的扩展性很强,支持HttpClient、HttpUrlConnection,甚至支持OkHttp,而且Volley里面也封装了ImageLoader,所以如果你愿意你甚至不需要使用图片加载框架,不过这块功能没有一些专门的图片加载框架强大,对于简单的需求可以使用,对于稍复杂点的需求还是需要用到专门的图片加载框架。

 

Android Volley完全解析(一),初识Volley的基本用法

http://blog.csdn.net/guolin_blog/article/details/17482095


(1)还记得搭建请求的第一步是什么吗?是新建一个请求队列,比如说这样:

RequestQueue queue = Volley.newRequestQueue(context)

虽然表面上只是一句代码的事情,但是背后做了很多准备工作,我们追踪源码,找到Volley#newRequestQueue()方法:

public static RequestQueue newRequestQueue(Context context, HttpStack stack, int maxDiskCacheBytes) 
首先我们看参数, 有三个,实际上我们默认使用了只有一个参数context的方法,这个是对应的重载方法,最终调用的是三个参数的方法,context是上下文环境;stack代表需要使用的网络连接请求类,这个一般不用设置,方法内部会根据当前系统的版本号调用不同的网络连接请求类(HttpUrlConnection和HttpClient);最后一个参数是缓存的大小。 接着我们看方法内部,这里先创 建了缓存文件 ,然后根 据不同的系统版本号实例化不同的请求类 ,用 stack引用这个类 。接着 又实例化了一个BasicNetwork ,这个类在下面会说到。然后到了实际实例化请求队列的地方: new RequestQueue(),这里接收两个参数,分别是缓存和network(BasicNetwork) 。实例化RequestQueue后,调用了 start() 方法,最后返回这个 RequestQueue
(2)我们跟着RequestQueue看看它的构造器做了哪些工作:
把传递过来的cache和network作为变量传递给了四个参数的构造器,在这里,初始化了RequestQueue的几个成员变量:mCache(文件缓存)、mNetwork(BasicNetwork实例)、mDispatchers(网络请求线程数组)、以及mDelivery(派发请求结果的接口)
(3)构造完RequestQueue后,从(1)可知,最后调用了它的start()方法,我们来看看这个方法, RequestQueue#start()
首先实例化了CacheDispatcher, CacheDispatcher类继承自Thread ,接着调用了它的start()方法, 开始了一条新的缓存线程 。接着是一个for循环,根据设置的mDispatchers数组大小来 开启多个网络请求线程 ,默认是 4条 网络请求线程。
  到目前为止,Volley.newRequestQueue()方法完成了,即我们的网络请求第一步,建立请求队列完成。
   先小结一下 建立请求队列所做的工作是,创建文件缓存(默认),实例化BasicNetwork,实例化Delivery用于发送线程请求,创建一条缓存线程和四条网络请求线程(默认)并运行。

art 2.网络请求的实现原理

在创建完请求队列后,接着就是建立一个请求,请求的方式可以是StringRequest、JsonArrayRequest或者ImageRequest等它继承自Request,而Request则是所有请求的父类
StringRequest源码:
主要关注的是 deliverResponse方法和parseNetworkResponse 可以看出,这两个方法都是重写的,我们翻看父类Request的对应方法,发现是抽象方法,说明这两个方法在每一个自定义的Request中都必须重写 。这里简单说说这两个方法的作用。先看 deliverResponse方法:它内部调用了mListener.onResponse(response)方法 ,而这个方法正是我们在写一个请求的时候,添加的listener所重写的onResponse方法,也就是说, 响应成功后在这里调用了onResponse()方法 接着看 pareNetworkResponse方法,可以看出这里主要是对response响应做出一些处理。 可以对比一下不同请求类的这个方法,都会不同的, 所以说,这个方法是针对不同的请求类型而对响应做出不同的处理 。比如说,如果是StringRequest,则将响应包装成String类型;如果是JsonObjectRequest,则将响应包装成JsonObject。那么现在应该清楚了 :对于想要得到某一种特殊类型的请求,我们可以自定义一个Request, 重写这两个方法即可。
  这里 小结一下: Request类做的工作主要是初始化一些参数,比如说请求类型、请求的url、错误的回调方法;而它的任一子类重写deliverResponse方法来实现成功的回调,重写parseNetworkResponse()方法来处理响应数据;至此,一个完整的Request请求搭建完毕。

Part 3.添加请求

前面已经完成了请求队列的创建,Request请求的创建,那么接下来就是把请求添加进队列了。我们看RequestQueue#add()源码

得出如下结论:在这个add方法中,主要判断一个Request请求是否可以缓存(默认是可以缓存的),如果不可以则直接添加到网络请求队列开始网络通信;如果可以,则进一步判断当前是否有相同的请求正在进行,如果有相同的请求,则让这个请求排队等待,如果没有相同的请求,则直接放进缓存队列中。如果对此还有什么疑问,可以看下面的流程图(图片来自网络):


Part 4.缓存线程

在part1的最后实例化了缓存线程并开始运行,一直处于等待状态,而上面把请求添加进了缓存线程,此时缓存线程就开始真正的工作了。我们来看缓存线程的源码,主要看它的run()方法,CacheDispatcher#run():

在run()方法中,我们可以看到最开始有一个 while(true)循环 ,表示它一直在等待缓存队列的新请求的出现。接着,先判断这个请求 是否有对应的缓存结果,如果没有则直接添加到网络请求队列 ;接着再 判断这个缓存结果是否过期了,如果过期则同样地添加到网络请求队列 ;接下来便是对缓存结果的处理了,我们可以看到,先是把缓存结果包装成NetworkResponse类,然后调用了 Request的parseNetworkResponse, 这个方法我们在part2说过,子类需要重写这个方法来处理响应数据。最后,把处理好的数据post到主线程,这里用到了ExecutorDelivery#postResponse()方法,下面会分析到。
   小结:CacheDispatcher线程主要对请求进行判断,是否已经有缓存,是否已经过期,根据需要放进网络请求队列。同时对相应结果进行包装、处理,然后交由ExecutorDelivery处理

Part 5.网络请求线程

上面提到,请求不能缓存、缓存结果不存在、缓存过期的时候会把请求添加进请求队列,此时一直等待的网络请求线程由于获取到请求,终于要开始工作了,我们来看NetworkDispatcher#run()方法

大体上和CacheDispatcher的逻辑相同,这里关注①号代码,这里调用了BasicNetwork#perfromRequest()方法,把请求传递进去,可以猜测,这个方法内部实现了网络请求的相关操作,那么我们进去看看, BasicNetwork#perfromRequest()
mHttpStack.performRequest();这里调用了mHttpStack的performRequest方法。
可以这么说:HurlStack封装好了HttpUrlConnection,而HttpClientStack封装了HttpClient。该方法返回了httpResponse,接着把这个响应交由②处处理,封装成NetworkResponse对象并返回。在NetworkDispatcher#run()方法获取返回的NetworkResponse对象后,对响应解析, 通过ExecutorDelivery#postResponse()方法回调解析出来的数据,这个过程和CacheDispatcher相同。

Part 6.ExecutorDelivery 通知主线程

在CacheDispatcher和NetworkDispatcher中最后都有调用到ExecutorDelivery#postResponse()方法,那么这个方法到底是做什么呢?由于缓存线程和网络请求线程都不是主线程,所以主线程需要有“人”通知它网络请求已经完成了,而这个“人”正是由ExecutorDelivery充当。在完成请求后,通过ExecutorDelivery#postResponse()方法,最终会回调到主线程中重写的onResponse()方法。我们看看这个方法的源码 ExecutorDelivery#postResponse()
public ExecutorDelivery(final Handler handler) {
        // Make an Executor that just wraps the handler.
        //实例化Executor,并且重写execute方法
        mResponsePoster = new Executor() {
            @Override
            public void execute(Runnable command) {
                //这里获取的handler是主线程的handler,可看part 1 (2)
                handler.post(command);
            }
        };
    }

execute()方法接收一个Runnable对象,那么我们回到上面的

mResponsePoster.execute(new ResponseDeliveryRunnable(request, response, runnable));

可以看出这里实例化了一个ResponseDeliveryRunnable对象作为Runnable对象。而这里的ResponseDeliveryRunnable则是当前类Executor的一个内部类,实现了Runnable接口,我们来看看:

/**
     * A Runnable used for delivering network responses to a listener on the
     * main thread.
     */
    @SuppressWarnings("rawtypes")
    private class ResponseDeliveryRunnable implements Runnable {
        private final Request mRequest;
        private final Response mResponse;
        private final Runnable mRunnable;

        //构造方法
        ...
        @Override
        public void run() {
            // If this request has canceled, finish it and don't deliver.
            if (mRequest.isCanceled()) {
                mRequest.finish("canceled-at-delivery");
                return;
            }

            // Deliver a normal response or error, depending.
            if (mResponse.isSuccess()) {
                mRequest.deliverResponse(mResponse.result);  // 1
            } else {
                mRequest.deliverError(mResponse.error);
            }
            ...
            }
       }
    }

在上面,①号代码回调到了Request的deliverResponse方法,即此时通知了主线程,请求已经完成,此时在Request子类重写的deliverResponse方法则会调用onResponse()方法,那么我们的Activity就能方便调用解析好的请求结果了。
  到目前为止,关于Volley的源码解析完毕。


https://www.jianshu.com/p/15e6209d2e6f

与HttpClient的对比

1.   HttpClient只是一个单纯的网络请求类库,比HttpUrlConnectionANDROIDSDK当中,Android2.3之前有问题)强大很多,可以对HTTP协议头和BODY部分进行方便的修改。     AndroidSDK本身也纳入了HttpClient,但处理文件上传和下传不行,还需要使用APACHE的HttpClient。HttpClient没有处理多线程问题,使用者需要配合AsyncTask来使用,AsyncTask处理了线程问题。

Volley的HttpStack提供了两种实现,分别使用了HttpUrlConnectionHttpClient,老版本使用了HttpClient,新版本加入了HttpUrlConnectionHttpStack实现,并且缺省是使用HttpUrlConnection,用户可通过设置来使用HttpClient的HttpStack实现。

2.   HttpClient没有提供缓存功能,而Volley实现图片缓存和HTTP的CACHE机制。

3.   HttpClient是不能在UI线程里面调用的,否则会出现ANR问题,而Volley是可以在UI线程里面调用的,因为它自己已经使用了线程池来做网络请求,使用者需要提供回调函数来出来网络响应。

4.   使用VOLLEY还需要考虑线程资源关闭的问题,而HttpClient不需要管理这些。

5.   因为线程池的问题,HttpClient是同步调用,而VOLLEY是异步调用。

 

如果我们实现一个Network访问的Façade,提供HttpClient和Volley两种实现,那么在接口定义上面就需要考虑这两个框架调用上的不同,同步和异步问题。还要考虑资源释放的问题。





  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值