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到主线程进行,通过
@Override public 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)方法.
@Override protected 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源码的全部解析.