从源码分析一次简单的volley请求
RequestQueue mRequestQueue = Volley.newRequestQueue(context);
StringRequest stringRequest = new StringRequest(url, new Listener<String>() {
@Override
public void onResponse(String arg0) {
}
}, new ErrorListener() {
@Override
public void onErrorResponse(VolleyError arg0) {
}
});
mRequestQueue .add(stringRequest );
一次简单的字符串网络请求如上,首先构造一个RequestQueue示例,再把请求用到的url,参数等封装到一个Request里面,最后把请求request添加到RequestQueue里就可以了。很简单。那么源码里做了哪些工作呢,现在我们一行一行的来分析。
先看这句Volley.newRequestQueue(context)的源码里在做什么呢。
Volley里重载了好多个newRequestQueue()静态方法,最终调用了
public static RequestQueue newRequestQueue(Context context, HttpStack stack, int maxDiskCacheBytes) {
File cacheDir = new File(context.getCacheDir(), "volley");
String userAgent = "volley/0";
try {
String network = context.getPackageName();
PackageInfo queue = context.getPackageManager().getPackageInfo(network, 0);
userAgent = network + "/" + queue.versionCode;
} catch (NameNotFoundException var7) {
;
}
if(stack == null) {
if(VERSION.SDK_INT >= 9) {
stack = new HurlStack();
} else {
stack = new HttpClientStack(AndroidHttpClient.newInstance(userAgent));
}
}
BasicNetwork network1 = new BasicNetwork((HttpStack)stack);
RequestQueue queue1;
if(maxDiskCacheBytes <= -1) {
queue1 = new RequestQueue(new DiskBasedCache(cacheDir), network1);
} else {
queue1 = new RequestQueue(new DiskBasedCache(cacheDir, maxDiskCacheBytes), network1);
}
queue1.start();
return queue1;
}
在这个方法里首先构建了缓存文件cacheDir ,然后就是构建网络请求的真正执行者stack,它分了版本,在sdk9之后,创建HurlStack,他是封装了HttpURLConnection来执行请求,sdk9.0之前创建HttpClientStack实例,他是封装了HttpClient来执行请求,这俩个类大家应该是熟悉的,为了统一两个类造成的差别,又把他们封装到了一个BasicNetwork中,由BasicNetwork来统一执行请求,这里用到了设计模式中的模板模式,HttpStack是个接口,里面定义了
HttpResponse performRequest(Request<?> var1, Map<String, String> var2);
BasicNetwork实现了Network接口,Network也只有一个接口
NetworkResponse performRequest(Request<?> var1)
一个请求的过程是由BasicNetwork调用HurlStack的performRequest,HurlStack再由其具体的子类HttpURLConnection或者HttpClient通过performRequest来真正的执行请求。
回到newRequestQueue(Context context, HttpStack stack, int maxDiskCacheBytes)这个方法,接下来是构建 RequestQueue实例,在构造函数里带着network1,估计请求执行的开始点又转移到RequestQueue中了。
接下来我们就来分析一下RequestQueue类。
public RequestQueue(Cache cache, Network network, int threadPoolSize, ResponseDelivery delivery) {
this.mSequenceGenerator = new AtomicInteger();
this.mWaitingRequests = new HashMap();//存放相同url的请求
this.mCurrentRequests = new HashSet();//存放所有的请求
this.mCacheQueue = new PriorityBlockingQueue();//存放不重复的请求
this.mNetworkQueue = new PriorityBlockingQueue();//存放要执行的网络请求
this.mFinishedListeners = new ArrayList();
this.mCache = cache;
this.mNetwork = network;//重Volley类传过来执行请求的类
this.mDispatchers = new NetworkDispatcher[threadPoolSize];//NetworkDispatcher是封装好的请求执行线程池,thredpoolsize默认是4。
this.mDelivery = delivery;
}
接下来我们再分析RequestQueue的start()方法源码,这个很重要。
public void start() {
this.stop();
this.mCacheDispatcher = new CacheDispatcher(this.mCacheQueue, this.mNetworkQueue, this.mCache, this.mDelivery);
this.mCacheDispatcher.start();
for(int i = 0; i < this.mDispatchers.length; ++i) {
NetworkDispatcher networkDispatcher = new NetworkDispatcher(this.mNetworkQueue, this.mNetwork, this.mCache, this.mDelivery);
this.mDispatchers[i] = networkDispatcher;
networkDispatcher.start();
}
}
CacheDispatcher这个是获取请求缓存结果的一个线程,重复的请求可以在这里直接获得结果。NetworkDispatcher在上面分析过其功能。从上面分析可知,queue1.start()之后,默认将会有5个线程开启,一个缓存线程,4个网络工作线程。Volley的整个机制就开始跑起来了,有网络请求的时候,就构造好request后,通过requeQueue的add()添加进去,至于这个请求是否直接或者请求结果,还是进行网络请求,则由requestQueue去调度了。所以接下来我们再分析一下add()方法,看看他是怎么调度网络请求的。
public <T> Request<T> add(Request<T> request) {
request.setRequestQueue(this);
Set var2 = this.mCurrentRequests;
synchronized(this.mCurrentRequests) {
this.mCurrentRequests.add(request);//所有的请求都会添加到mCurrentRequests
}
request.setSequence(this.getSequenceNumber());//确定请求的序列号
request.addMarker("add-to-queue");
//从这里开始有调度策略了
if(!request.shouldCache())
{ //不需要缓存结果的直接扔给网络队列去网络请求
this.mNetworkQueue.add(request);
return request;
} else {
Map var7 = this.mWaitingRequests;
synchronized(this.mWaitingRequests) {
String cacheKey = request.getCacheKey();//返回request的url作为缓存key
if(this.mWaitingRequests.containsKey(cacheKey)) {
//重复的请求放到相同key的队列里
Object stagedRequests = (Queue)this.mWaitingRequests.get(cacheKey);
if(stagedRequests == null) {
stagedRequests = new LinkedList();
}
((Queue)stagedRequests).add(request);
this.mWaitingRequests.put(cacheKey, stagedRequests);
if(VolleyLog.DEBUG) {
}
} else {
this.mWaitingRequests.put(cacheKey, (Object)null);
this.mCacheQueue.add(request);
}
return request;
}
}
}
最后我们再分析CacheDispatcher和NetworkDispatcher。
再requestQueue的start()方法中,创建了这两个类的,开启了线程。
创建CacheDispatcher时候CacheDispatcher(this.mCacheQueue, this.mNetworkQueue, this.mCache, this.mDelivery);
带进去了
this.mCacheQueue = new PriorityBlockingQueue();//存放不重复的请求
this.mNetworkQueue = new PriorityBlockingQueue();//存放要执行的网络请求
这两个参数,再看他的run()方法
public void run() {
if(DEBUG) {
VolleyLog.v("start new dispatcher", new Object[0]);
}
Process.setThreadPriority(10);
this.mCache.initialize();
while(true) {
while(true) {
while(true) {
while(true) {
try {
while(true) {
//从对列中取出一个请求
final Request e = (Request)this.mCacheQueue.take();
e.addMarker("cache-queue-take");
if(e.isCanceled()) {
//请求取消了就结束这个请求
e.finish("cache-discard-canceled");
} else {
Entry entry = this.mCache.get(e.getCacheKey());
//检查缓存里是否有对应结果了
if(entry == null) {
e.addMarker("cache-miss");
//没有缓存就扔进网络执行对列里
this.mNetworkQueue.put(e);
} else if(entry.isExpired()) {
//缓存过期也扔进网络执行对列里再请求一次
e.addMarker("cache-hit-expired");
e.setCacheEntry(entry);
this.mNetworkQueue.put(e);
} else {
e.addMarker("cache-hit");
Response response = e.parseNetworkResponse(new NetworkResponse(entry.data, entry.responseHeaders));
e.addMarker("cache-hit-parsed");
if(entry.refreshNeeded()) {
//如果需要刷新,也会扔到网络执行对列里执行
e.addMarker("cache-hit-refresh-needed");
e.setCacheEntry(entry);
response.intermediate = true;
this.mDelivery.postResponse(e, response, new Runnable() {
public void run() {
try {
CacheDispatcher.this.mNetworkQueue.put(e);
} catch (InterruptedException var2) {
;
}
}
});
} else {
//没有上述约束,直接传递结果到主线程
this.mDelivery.postResponse(e, response);
再看看NetworkDispatcher怎么执行的
public NetworkDispatcher(BlockingQueue<Request<?>> queue, Network network, Cache cache, ResponseDelivery delivery) {
this.mQueue = queue;//从requestQueue传进来的请求对列
this.mNetwork = network;//网络请求的执行者
this.mCache = cache;
this.mDelivery = delivery;
}
再看看他的run方法
public void run() {
Process.setThreadPriority(10);
while(true) {
long startTimeMs;
Request request;
while(true) {
startTimeMs = SystemClock.elapsedRealtime();
try {
//从执行对列里取出一个请求
request = (Request)this.mQueue.take();
break;
} catch (InterruptedException var6) {
if(this.mQuit) {
return;
}
}
}
try {
request.addMarker("network-queue-take");
if(request.isCanceled()) {
//请求取消了就结束请求
request.finish("network-discard-cancelled");
} else {
this.addTrafficStatsTag(request);
//由mNetwork去执行网络请求
NetworkResponse e = this.mNetwork.performRequest(request);
request.addMarker("network-http-complete");
if(e.notModified && request.hasHadResponseDelivered()) {
//如果请求的内容没修改过,并且已经发送大主线程了,就结束掉
request.finish("not-modified");
} else {
Response volleyError1 = request.parseNetworkResponse(e);
request.addMarker("network-parse-complete");
if(request.shouldCache() && volleyError1.cacheEntry != null) {
//如果请求需要缓存并且结果不为空,则把结果缓存起来
this.mCache.put(request.getCacheKey(), volleyError1.cacheEntry);
request.addMarker("network-cache-written");
}
request.markDelivered();
this.mDelivery.postResponse(request, volleyError1);
}
}
} catch (VolleyError var7) {
var7.setNetworkTimeMs(SystemClock.elapsedRealtime() - startTimeMs);
this.parseAndDeliverNetworkError(request, var7);
} catch (Exception var8) {
VolleyLog.e(var8, "Unhandled exception %s", new Object[]{var8.toString()});
VolleyError volleyError = new VolleyError(var8);
volleyError.setNetworkTimeMs(SystemClock.elapsedRealtime() - startTimeMs);
this.mDelivery.postError(request, volleyError);
}
}
}
到这里,volley的网络请求机制就基本出来了。
再分享一个点,Request有好多个子类,如StringRequest,JsonRequest,ImageRequest
,他们有什么区别呢,在上面有行解析NetworkResponse 的代码
esponse volleyError1 = request.parseNetworkResponse(e);
这几个子类解析出来对应的结果都不同,
如StringRequest
protected Response<String> parseNetworkResponse(NetworkResponse response) {
String parsed;
try {
parsed = new String(response.data, HttpHeaderParser.parseCharset(response.headers));
} catch (UnsupportedEncodingException var4) {
parsed = new String(response.data);
}
return Response.success(parsed, HttpHeaderParser.parseCacheHeaders(response));
}
就是解析出了一个字符串。
在看看JsonobjectRequest
protected Response<JSONObject> parseNetworkResponse(NetworkResponse response) {
try {
String je = new String(response.data, HttpHeaderParser.parseCharset(response.headers, "utf-8"));
return Response.success(new JSONObject(je), HttpHeaderParser.parseCacheHeaders(response));
} catch (UnsupportedEncodingException var3) {
return Response.error(new ParseError(var3));
} catch (JSONException var4) {
return Response.error(new ParseError(var4));
}
}
返回给主线程的就是个jsonobject
最后看看ImageRequest
private Response<Bitmap> doParse(NetworkResponse response) {
byte[] data = response.data;
Options decodeOptions = new Options();
Bitmap bitmap = null;
if(this.mMaxWidth == 0 && this.mMaxHeight == 0) {
decodeOptions.inPreferredConfig = this.mDecodeConfig;
bitmap = BitmapFactory.decodeByteArray(data, 0, data.length, decodeOptions);
} else {
decodeOptions.inJustDecodeBounds = true;
BitmapFactory.decodeByteArray(data, 0, data.length, decodeOptions);
int actualWidth = decodeOptions.outWidth;
int actualHeight = decodeOptions.outHeight;
int desiredWidth = getResizedDimension(this.mMaxWidth, this.mMaxHeight, actualWidth, actualHeight, this.mScaleType);
int desiredHeight = getResizedDimension(this.mMaxHeight, this.mMaxWidth, actualHeight, actualWidth, this.mScaleType);
decodeOptions.inJustDecodeBounds = false;
decodeOptions.inSampleSize = findBestSampleSize(actualWidth, actualHeight, desiredWidth, desiredHeight);
Bitmap tempBitmap = BitmapFactory.decodeByteArray(data, 0, data.length, decodeOptions);
if(tempBitmap == null || tempBitmap.getWidth() <= desiredWidth && tempBitmap.getHeight() <= desiredHeight) {
bitmap = tempBitmap;
} else {
bitmap = Bitmap.createScaledBitmap(tempBitmap, desiredWidth, desiredHeight, true);
tempBitmap.recycle();
}
}
return bitmap == null?Response.error(new ParseError(response)):Response.success(bitmap, HttpHeaderParser.parseCacheHeaders(response));
}
最后返回了一个bitmap