Volley源码分析
来源:互联网 发布:exceed2008是什么软件 编辑:程序博客网 时间:2024/06/05 06:36
Volley源码分析
流程图
注:流程图有错,网络请求线程应该默认为四个
请求初始化
我们使用volley框架,一般会先创建请求队列 mRequestQueue = Volley.newRequestQueue(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); }
这个一个参数的构造最终会走public static RequestQueue newRequestQueue(Context context, HttpStack stack, int maxDiskCacheBytes)这个构造,stack值为null,maxDiskCacheBytes值为-1,代表使用默认的HttpStack和默认磁盘缓存大小,该构造代码如下:
//磁盘缓存目录,在data/data/包名/cache/volley目录 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) { } //因为默认stack为null,所以会根据sdk版本创建不同的HttpStack,其中HurlStack是用HttpURLConnection进行网络请求的 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)); } } //创建一个BasicNetwork对象,Network是一个接口,有一个方法public NetworkResponse performRequest(Request<?> request); 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;
其中queue = new RequestQueue(new DiskBasedCache(cacheDir), network)创建请求队列中new DiskBasedCache(cacheDir)会走如下构造,创建默认大小为5MB的磁盘缓存
public DiskBasedCache(File rootDirectory) { this(rootDirectory, DEFAULT_DISK_USAGE_BYTES); }
而new RequestQueue(new DiskBasedCache(cacheDir), network)构造最终会走这个构造:
public RequestQueue(Cache cache, Network network, int threadPoolSize, ResponseDelivery delivery) { mCache = cache; mNetwork = network; mDispatchers = new NetworkDispatcher[threadPoolSize]; mDelivery = delivery; }
由以上代码可以看出,系统会创建一个网络分发线程数组mDispatchers,线程数默认为4,并创建一个响应分发器mDelivery
private static final int DEFAULT_NETWORK_THREAD_POOL_SIZE = 4; private final ResponseDelivery mDelivery; private NetworkDispatcher[] mDispatchers;
至此,请求队列初始化完毕
请求队列启动
请求队列启动是调用queue.start()方法,具体实现如下
/** * Starts the dispatchers in this queue. */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,其实它也是个线程,并其启动它;然后遍历网络分发线程数组mDispatchers,创建网络请求线程,赋值并启动网络分发线程数组,其长度为4,也就是有4个网络请求线程,创建缓存线程和网络请求线程构造都有四个参数,mCacheQueue, mNetworkQueue, mCache, mDelivery;其中 mCache, mDelivery前面讲过一个是缓存对象,一个是响应分发器,其余两个是缓存请求队列和网络请求队列,之后我们创建的网络请求就会按情况添加到队列中.
线程启动会走run()方法,我们先看缓存线程run方法
public void run() { if (DEBUG) VolleyLog.v("start new dispatcher"); Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND); // Make a blocking call to initialize the cache. mCache.initialize(); Request<?> request; while (true) { // release previous request object to avoid leaking request object when mQueue is drained. request = null; try { // Take a request from the queue. request = mCacheQueue.take(); } catch (InterruptedException e) { // We may have been interrupted because it was time to quit. if (mQuit) { return; } continue; } ...}
从这里可以看出mCacheQueue.take(),缓存队列会监视队列中的请求,如果有就会取出,然后处理,网络请求队列也是如此,在这之前我们先看这个mCache.initialize(),缓存的初始化:
public synchronized void initialize() { if (!mRootDirectory.exists()) { if (!mRootDirectory.mkdirs()) { VolleyLog.e("Unable to create cache dir %s", mRootDirectory.getAbsolutePath()); } return; } File[] files = mRootDirectory.listFiles(); if (files == null) { return; } for (File file : files) { BufferedInputStream fis = null; try { fis = new BufferedInputStream(new FileInputStream(file)); CacheHeader entry = CacheHeader.readHeader(fis); entry.size = file.length(); //将缓存的头信息存入集合中 putEntry(entry.key, entry); } catch (IOException e) { if (file != null) { file.delete(); } } finally { try { if (fis != null) { fis.close(); } } catch (IOException ignored) { } } }}
其中putEntry(entry.key, entry)会先把缓存的头信息取出来存入Map<> mEntries中,而不会读取缓存,到请求发生时才会读取缓存,这样既节约了时间,又避免内存溢出.
网络请求处理
缓存线程的请求处理
我们会调用RequestQueue的add(Request request)方法将请求添加进队列,由于缓存线程已启动,就会取出这个请求,进行处理:
try { request.addMarker("cache-queue-take"); // If the request has been canceled, don't bother dispatching it. //请求取消 if (request.isCanceled()) { request.finish("cache-discard-canceled"); continue; } // Attempt to retrieve this item from cache. //没有缓存,将请求添加进网络请求队列 Cache.Entry entry = mCache.get(request.getCacheKey()); if (entry == null) { request.addMarker("cache-miss"); // Cache miss; send off to the network dispatcher. mNetworkQueue.put(request); continue; } // If it is completely expired, just send it to the network. //缓存过期,将请求添加进网络请求队列 if (entry.isExpired()) { request.addMarker("cache-hit-expired"); request.setCacheEntry(entry); mNetworkQueue.put(request); continue; } // We have a cache hit; parse its data for delivery back to the request. request.addMarker("cache-hit"); Response<?> response = request.parseNetworkResponse( new NetworkResponse(entry.data, entry.responseHeaders)); request.addMarker("cache-hit-parsed"); if (!entry.refreshNeeded()) { // Completely unexpired cache hit. Just deliver the response. mDelivery.postResponse(request, response); } else { // Soft-expired cache hit. We can deliver the cached response, // but we need to also send the request to the network for // refreshing. request.addMarker("cache-hit-refresh-needed"); request.setCacheEntry(entry); // Mark the response as intermediate. response.intermediate = true; // Post the intermediate response back to the user and have // the delivery then forward the request along to the network. final Request<?> finalRequest = request; mDelivery.postResponse(request, response, new Runnable() { @Override public void run() { try { mNetworkQueue.put(finalRequest); } catch (InterruptedException e) { // Not much we can do about this. } } }); } } catch (Exception e) { VolleyLog.e(e, "Unhandled exception %s", e.toString()); }
由上面可以看出,当缓存找到了并且不过期,就会从缓存中读取数据,通过Response<> response = request.parseNetworkResponse(new NetworkResponse(entry.data, entry.responseHeaders));将我们实现的parseNetworkResponse方法调用并返回Response对象
最后调用mDelivery.postResponse(request, response),其中mDelivery就是我们初始化请求队列时创建的响应分发器
public RequestQueue(Cache cache, Network network, int threadPoolSize) { this(cache, network, threadPoolSize, new ExecutorDelivery(new Handler(Looper.getMainLooper()))); }
该分发器绑定一个主线程的handler,会在将响应post到主线程进行,通过
@Overridepublic void postResponse(Request<?> request, Response<?> response, Runnable runnable) { request.markDelivered(); request.addMarker("post-response"); mResponsePoster.execute(new ResponseDeliveryRunnable(request, response, runnable));}
执行ResponseDeliveryRunnable的run()方法,
if (mResponse.isSuccess()) { mRequest.deliverResponse(mResponse.result); } else { mRequest.deliverError(mResponse.error); }
从这里可以看到,mRequest会调用deliverResponse和deliverError方法最终会回调我们实现的onResponse(response)和onErrorResponse(error)方法.
@Overrideprotected void deliverResponse(T response) { if (mListener != null) { mListener.onResponse(response); }}public void deliverError(VolleyError error) { if (mErrorListener != null) { mErrorListener.onErrorResponse(error); }}
网络线程的请求处理
网络线程的请求处理跟缓存线程的请求处理大致相同,只不过要从网络获取数据,再缓存到本地磁盘,然后再由响应分发器分发到主线程
try { request.addMarker("network-queue-take"); // If the request was cancelled already, do not perform the // network request. if (request.isCanceled()) { request.finish("network-discard-cancelled"); continue; } addTrafficStatsTag(request); // Perform the network request. //请求网络数据 NetworkResponse networkResponse = mNetwork.performRequest(request); request.addMarker("network-http-complete"); // If the server returned 304 AND we delivered a response already, // we're done -- don't deliver a second identical response. if (networkResponse.notModified && request.hasHadResponseDelivered()) { request.finish("not-modified"); continue; } // Parse the response here on the worker thread. //解析数据 Response<?> response = request.parseNetworkResponse(networkResponse); request.addMarker("network-parse-complete"); // Write to cache if applicable. // TODO: Only update cache metadata instead of entire record for 304s. //缓存到本地磁盘 if (request.shouldCache() && response.cacheEntry != null) { mCache.put(request.getCacheKey(), response.cacheEntry); request.addMarker("network-cache-written"); } // Post the response back. request.markDelivered(); mDelivery.postResponse(request, response); } catch (VolleyError volleyError) { volleyError.setNetworkTimeMs(SystemClock.elapsedRealtime() - startTimeMs); parseAndDeliverNetworkError(request, volleyError); } catch (Exception e) { VolleyLog.e(e, "Unhandled exception %s", e.toString()); VolleyError volleyError = new VolleyError(e); volleyError.setNetworkTimeMs(SystemClock.elapsedRealtime() - startTimeMs); mDelivery.postError(request, volleyError); }
其中请求网络数据通过NetworkResponse networkResponse = mNetwork.performRequest(request)实现,mNetwork就是初始化时的Network network = new BasicNetwork(stack),sdk版本9以上是使用
BasicNetwork类 public NetworkResponse performRequest(Request<?> request) throws VolleyError { ... httpResponse = mHttpStack.performRequest(request, headers);}HttpStack类 public NetworkResponse performRequest(Request<?> request) throws throws IOException, AuthFailureError { ... HttpURLConnection connection = openConnection(parsedUrl, request);}
以上就是volley源码的全部解析.
- Android-Volley源码分析
- [Android]volley源码分析
- Volley源码分析
- Volley源码分析
- Volley源码分析
- Volley -- 源码分析
- Android-Volley源码分析
- Volley源码流程分析
- Volley源码分析
- Volley源码个人分析
- Volley框架源码分析
- Volley源码分析一
- Volley 源码分析
- Volley源码分析二
- volley源码分析
- volley源码分析
- Volley(2)源码分析
- Volley 源码分析
- lightoj 1011 Marriage Ceremonies (状压dp)
- SDL初步学习
- 【Codeforces Round #366 (Div. 2)】Codeforces 705B Spider Man
- os引导程序boot从扇区拷贝os加载程序loader文件到内存(boot copy kernel to mem in the same method)
- UVA 10006(素数判断+快速幂)
- Volley源码分析
- 学习DWZ框架小结
- monkeyrunner自动化测试
- 【web前端技术】八款JS(javascript)常用开发框架介绍及比较(web前端开发框架)
- 《一个操作系统的实现》——pmtest1.asm详解
- 包的误用
- ubuntu14 apt-get 简单 安装 ffmpeg
- MVC使用jQuery从视图向控制器传递Model,数据验证,MVC HTML辅助方法小结
- 【Codeforces Round #368 (Div. 2)】Codeforces 707A Brain's Photos