Volley源码解析 --- Volley组成(1)
来源:互联网 发布:淘宝网衬衫连衣裙女 编辑:程序博客网 时间:2024/05/19 19:12
简介
volley框架是Google公司开发的一套网络访问开源框架,具有体积小、效率高和适合频繁的网络请求等特点;虽然现在的网络主流都推荐用Retrofit+Okhttp,但是lz认为用什么样的网络框架还是得根据什么样的项目,不是一种功夫就可以打遍天下无敌手的;所有这里分析Volley的目的不一定是去用,而是学习分析Volley的代码设计、网络请求、缓存设计等知识,补充我们的知识,更好的帮助我们开发今后的工作。
知识点简介
本文将以以下几个方面逐点分析
+ Volley由哪些重要的成员组成 ?
+ Volley执行的流程如何以及它的成员运行流程如何 ?
+ Volley一些特性点怎么实现,缓存设计、HTTPS等
Volley重要成员
NetWork.java
网络控制中心,执行真正的网络请求部分,所有的请求最终执行网络访问就是它来完成的
Request.java
Volley提供的网络请求类,封装网络请求参数
RequestQueue.java
这个类很重要,网络请求队列类,所有的Request都是要add到这个类中,而网络线程和缓存线程都是从这个队列里面去取
CacheDispatcher.java
缓存线程,默认只有一个,这个线程用于处理一些具有缓存特性的请求任务,如果有缓存就去缓存中取,没有或者该任务是实时性的,就需要重新把该任务添加到网络线程中去执行
NetworkDispatcher.java
网络线程,所有的网络请求都是由这类型网络线程发出执行的,Volley默认该线程由4个,协同处理所有的请求Request任务
数据结构:
Set
Volley源码分享 – 从最简单的使用方法入手
RequestQueue queue = Volley.newRequestQueue(this);StringRequest request = new StringRequest(Request.Method.GET, "https://www.baidu.com/", new Response.Listener<String>() { @Override public void onResponse(String response) { tv.setText(response); } }, new Response.ErrorListener() { @Override public void onErrorResponse(VolleyError error) { tv.setText("error"+error.getMessage()); } }); queue.add(request);
Volley.newRequestQueue(this)
追踪进去发现它调用了另一个方法newRequestQueue(Context context, HttpStack stack)
public static RequestQueue newRequestQueue(Context context, HttpStack stack) { File cacheDir = new File(context.getCacheDir(), DEFAULT_CACHE_DIR); ...... if (stack == null) { if (Build.VERSION.SDK_INT >= 9) { stack = new HurlStack(); //内部使用HttpURLConnection } else { //内部使用HttpClient,但是现在已经无法使用了 stack = new HttpClientStack(AndroidHttpClient.newInstance(userAgent)); } } Network network = new BasicNetwork(stack); RequestQueue queue = new RequestQueue(new DiskBasedCache(cacheDir), network); queue.start(); return queue; }
以上任务有三:
1. 创建缓存目录;
2. 实例化网络控制核心NetWork,api>9使用HurlStack,<9的使用HttpClient,追踪AndroidHttpClient.newInstance,发现它直接抛了一个异常,说明现在<9的是无法使用Volley
3. 实例化RequestQueue,并传递了缓存类和网络控制类,RequestQueue很重要,继续分析:
RequestQueue构造方法
public RequestQueue(Cache cache, Network network) { this(cache, network, DEFAULT_NETWORK_THREAD_POOL_SIZE); }public RequestQueue(Cache cache, Network network, int threadPoolSize) { this(cache, network, threadPoolSize, new ExecutorDelivery(new Handler(Looper.getMainLooper()))); }public RequestQueue(Cache cache, Network network, int threadPoolSize, ResponseDelivery delivery) { mCache = cache; mNetwork = network; mDispatchers = new NetworkDispatcher[threadPoolSize]; mDelivery = delivery; }
上面完成了RequestQueue的成员赋值,实例化了DEFAULT_NETWORK_THREAD_POOL_SIZE(4)个网络线程,还加上一个回调到主线程的工具类ExecutorDelivery;ExecutorDelivery就是内部封装了handler.postRunnable方法,具体可以点击查看源码
回到newRequestQueue执行queue.start()
public void start() { stop(); // Make sure any currently running dispatchers are stopped. // 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(); } }
默认情况下,是创建一个CacheDispatcher缓存线程和4个NetworkDispatcher网络线程并运行,它们两个的大致工作就是轮询去mCacheQueue或者mNetworkQueue队列取出Request请求,并执行;
上面代码还有一个很重要的知识点,当前线程如何停止其他线程?解决办法就是该方法的第一条stop()方法,Java默认是无法直接停止其他线程的,只有利用interrupt产生中断异常,由其他线程设置标志位自行完结自己
回到Volley最简单的用法 — RequestQueue.add(Request)
上面示例的StringRequest不是设计主要的就暂不分析了,如有兴趣的可点击这里
public <T> Request<T> add(Request<T> 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); //所有的Request都要加入mCurrentRequests队列中去,方便管理 } // 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<>(); } 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; } }
以上完成任务:
1. 将所有Request都加入mCurrentRequests这个Set集合里面来,方便管理;比如有时想取消某个Request就会从set.remove(Request)
2. 如果Request任务不是一个缓存特性的请求,就直接加入到mNetworkQueue队列去,方法结束
3. Request是一个缓存特性,就要根据一定的逻辑加入到mCacheQueue队列里面去;分析这个逻辑:
Map
if (request.shouldCache()) { synchronized (mWaitingRequests) { String cacheKey = request.getCacheKey(); Queue<Request<?>> waitingRequests = mWaitingRequests.remove(cacheKey); if (waitingRequests != null) { if (VolleyLog.DEBUG) { VolleyLog.v("Releasing %d waiting requests for cacheKey=%s.", waitingRequests.size(), cacheKey); } // Process all queued up requests. They won't be considered as in flight, but // that's not a problem as the cache has been primed by 'request'. mCacheQueue.addAll(waitingRequests); } } }
它会将相同的key的value,从mWaitingRequests的Map集合中取出来,在从新假如到mCacheQueue中去,在CacheDispatcher线程中在轮训mCacheQueue队列把上次网络访问的数据赋值给新的请求,就不必再从新进行一次网络请求
总结
一张流程图
至此,RequestQueue重要方法已经分析差不多了;以上是lz一点见解,如有不足还请指教;明天再继续分析CacheDispatcher和NetworkDispatcher线程执行流程
- Volley源码解析 --- Volley组成(1)
- 【Volley】Volley源码解析
- Volley尝试源码解析1
- Volley 源码解析(一)
- Volley 源码解析(二)
- Volley源码解析(一)
- Volley源码解析(二)
- Volley源码解析(三)
- 《Volley源码分析》Part2、Volley源码解析
- volley源码解析
- Volley 源码解析
- Volley 源码解析
- Volley 源码解析
- Volley 源码解析
- Volley 源码解析
- Volley 源码解析
- Volley 源码解析
- Volley 源码解析
- Spring实现AOP的多种方式
- 1.[easy] Two Sum
- Java Condition 的await(), singal(), singalAll() 具体代码实现分析,
- Room---SQLite库
- 【从入门到放弃】WEB前端之HTML+CSS基础01
- Volley源码解析 --- Volley组成(1)
- 超出内容之后 省略号(...) --ellipsis
- OSI七层与TCP/IP五层网络架构详解
- 【收藏】全球100款大数据工具汇总
- 斐波那契数列
- 图论
- 敌兵布阵,线段树入门。
- Java-Socket
- 卖火柴的小女孩