Volley源码解析(一),基本概述

来源:互联网 发布:赛事专用软件源码php 编辑:程序博客网 时间:2024/05/21 06:57
    最近在学习Volley源码及android网络框架的构建,由此写下这篇博客作为学习的第一步总结,待将Volley源码解析完后,如果有时间也会写关于搭建android网络框架的文章,更希望能帮助到大家在这一块的学习,由   于本人的能力与时间有限,有什么不足之处还请各位指正,谢谢!!!    本文的结构分为三个部分,第一部分为Volley的总体框架的关系;第二部分是我们使用Volley框架时的运行原理;第三部分为Volley中一些核心的类的作用。下面开启我们的Volley学习之旅吧。


一、总体架构的关系:

这里写图片描述

    本图片中的其中蓝色部分代表主线程,也就是activity运行的UI线程,绿色部分代表缓存线程Cache类,橙色部分代表网络线程主要是Network类。Volley默认的是一个缓存线程与4个网络线程,我们在主线程中调用RequestQueue的add()方法来添加一条网络请求,这条请求会先被加入到缓存队列当中,HTTP请求,解析响应结果,写入缓存,并回调主线程。


二、Volley的使用原理:

以StringRequest为例,且sdk大于9,当我们在使用volley时,一般会这样写:

//获取到一个RequestQueue请求队列对象,它可以缓存所有的HTTP请求,然后按照一定的算法并发地发出这些请求。RequestQueue mQueue = Volley.newRequestQueue(context);//创建一个StringRequest对象,此请求为Get请求StringRequest stringRequest = new StringRequest("http://www.baidu.com",                      new Response.Listener<String>() {                          @Override                          public void onResponse(String response) {                              Log.d("TAG", response);                          }                      }, new Response.ErrorListener() {                          @Override                          public void onErrorResponse(VolleyError error) {                              Log.e("TAG", error.getMessage(), error);                          }                      });  //将这个StringRequest对象添加到RequestQueue里面就可以了mQueue.add(stringRequest);  

当程序调用上面第一行代码时的运行逻辑图:

这里写图片描述

第一行的这么一句代码是至关重要的,为后面的网络请求做好了准备。第一步创建cacheDir目录用于网络请求的缓存。第二步创建Network,用于执行StringRequest请求,其中有一个重要方法performRequest()将参数request提取关键数据,调用mHttpStack.performRequest()发起网络访问,分解反馈httpResponse的statusCode封装不同的NetworkResponse。第三步创建RequestQueue消息队列,消息队列维护了提交给网络框架的请求列表,并且根据相应的规则进行排序。默认情况下根据优先级和进入队列的顺序来执行,该队列使用的是线程安全的PriorityBlockingQueue,因为我们的队列会被并发的访问,因此需要保证访问的原子性。的请求队列,请求完成之后将结果投递给UI线程。


源代码如下:
public static RequestQueue newRequestQueue(Context context, HttpStack stack) {    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 = new RequestQueue(new DiskBasedCache(cacheDir), network);    queue.start();    return queue;}

结合上面的图,源代码还是很好理解的,在此就不重复了。

当程序调用第二行时的运行逻辑图:

此时只是进行一些参数的设置,以及接口返回数据的处理。
这里写图片描述

源代码如下:
public StringRequest(int method, String url, Listener<String> listener, ErrorListener errorListener) {    super(method, url, errorListener);    mListener = listener;//数据请求信息回应的一个监听}
super的源码如下:
public Request(int method, String url, Response.ErrorListener listener) {    mMethod = method;    mUrl = url;    mErrorListener = listener;    setRetryPolicy(new DefaultRetryPolicy()); //设置优先级    mDefaultTrafficStatsTag = TextUtils.isEmpty(url) ? 0: Uri.parse(url).getHost().hashCode(); //设置活动标签}<br/>

当调用最后一行时的运行逻辑图:

这里写图片描述
通过这句代码,对新add的request,设置归属队列,放入mCurrentRequest表示正大处理,并设置一下加入队列的顺序,设置是否需要对
request进行cache。此时网络请求已经准备就绪了,等待NetworkDispatcher的处理。

源代码如下:
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);    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();        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);        }        return request;    }}


三、Volley中的一些类的概念

Volley:通过 newRequestQueue(…) 函数新建并启动一个请求队列RequestQueue。
Request:表示一个请求的抽象类。StringRequest、JsonRequest、ImageRequest ,MultipartRequest都是它的子类,表示某种类型的请求。
RequestQueue:表示请求队列,里面包含一个CacheDispatcher(用于处理缓存请求的调度线程)、NetworkDispatcher数组(用于处理网络请求的调度线程),一个ResponseDelivery(返回结果分发接口),通过 start() 函数启动时会启动CacheDispatcher和NetworkDispatchers。
CacheDispatcher:一个线程,用于调度处理走缓存的请求。启动后会不断从缓存请求队列中取请求处理,队列为空则等待,请求处理结束则将结果传递给ResponseDelivery去执行后续处理。当结果未缓存过、缓存失效或缓存需要刷新的情况下,该请求都需要重新进入NetworkDispatcher去调度处理。
NetworkDispatcher:一个线程,用于调度处理走网络的请求。启动后会不断从网络请求队列中取请求处理,队列为空则等待,请求处理结束则将结果传递给ResponseDelivery去执行后续处理,并判断结果是否要进行缓存。
ResponseDelivery:返回结果分发接口,目前只有基于ExecutorDelivery的在入参 handler 对应线程内进行分发。
HttpStack:处理 Http 请求,返回请求结果。目前 Volley 中有基于 HttpURLConnection 的HurlStack和 基于 Apache HttpClient 的HttpClientStack。
Network:调用HttpStack处理请求,并将结果转换为可被ResponseDelivery处理的NetworkResponse。
Cache:缓存请求结果,Volley 默认使用的是基于 sdcard 的DiskBasedCache。NetworkDispatcher得到请求结果后判断是否需要存储在 Cache,CacheDispatcher会从 Cache 中取缓存结果。
其他还有许多细节完善的类,在此就不多提了,每个类都有其固定的功能,而且分工明确,核心的几个类基本列出。

今天的总结就先到这里了。下期再见!!!
1 0
原创粉丝点击