在年初的时候,就一直在想,将圈内的几个流行的网络框架的源码分析分析,可是又可是水平不够,有些分析的很差,那就尴尬了....因此花了点时间好好看了一下,走了一遍这些源码,决定试一试,至关于作个笔记吧。今天就从一个相对轻量级的网络请求框架下手--Volley。面试
提起这个Volley,不少同窗应该都很熟悉,可是我面试过蛮多人,问起,对volley的了解,基本上就说,里面对图片作了缓存,在2.3以前用的是HTTPClient, 2.3后用的是HttpURLConnection,而后就没了.... 虽然这没什么错,可是对于一个有经验的开发人员来讲,这样的认识,太过于表面了。咱们知道Volley是 在2013年Google I/O大会上推出了一个新的网络通讯框架,他的设计目的就是为了那些请求数据量不是特别大,可是又是特别频繁的网络操做很是适合。可是对于 数据量较大的请求,好比说下载一个较大的文件,Volley可能相比于其余的框架,就有点不足了....缓存
我这里是以依赖架包的形式 ,你们也能够以gradle的形式进行依赖。bash
1 //获取volley的请求对象
2 RequestQueue requestQueue = Volley.newRequestQueue(getApplicationContext());
3 StringRequest stringRequest = new StringRequest(StringRequest.Method.GET, "http://www.baidu.com", new Response.Listener<String>() {
4 @Override
5 public void onResponse(String s) {
6 Log.d("MainActivity", "----->" + s);
7
8 }
9 }, new Response.ErrorListener() {
10 @Override
11 public void onErrorResponse(VolleyError volleyError) {
12 Log.d("MainActivity", "---volleyError-->" + volleyError);
13 }
14 });
15 requestQueue.add(stringRequest);
从代码能够看出,首先newRequestQueue来获取到一个请求队列,而后在将StringRequest这个请求添加到请求队列中,就能够了,就是这么简单。固然请求不值
StringRequest,还有JsonObjectRequest ,ImageRequest等等可是用法都是同样的,这里就不贴代码了。接着...就没了,Volley的简单使用就这样能够进行请
求了。是否是很简单....
咱们先看看newRequestQueue这个内部是怎么执行的,代码一开始连续执行了几个重载方法,最后走到newRequestQueue
1 public static RequestQueue newRequestQueue(Context context, HttpStack stack, int maxDiskCacheBytes) {
2 File cacheDir = new File(context.getCacheDir(), "volley");
3 String userAgent = "volley/0";
4
5 try {
6 String packageName = context.getPackageName();
7 PackageInfo info = context.getPackageManager().getPackageInfo(packageName, 0);
8 userAgent = packageName + "/" + info.versionCode;
9 } catch (NameNotFoundException var7) {
10 ;
11 }
12
13 //这里进行了一个版本的判断 2.3以前用的是HTTPClient,2.3以后使用的是HttpURLConnection
14 if (stack == null) {
15 if (VERSION.SDK_INT >= 9) {
16 stack = new HurlStack();
17 } else {
18 stack = new HttpClientStack(AndroidHttpClient.newInstance(userAgent));
19 }
20 }
21
22 Network network = new BasicNetwork((HttpStack)stack);
23 RequestQueue queue;
24 if (maxDiskCacheBytes <= -1) {
25 queue = new RequestQueue(new DiskBasedCache(cacheDir), network);
26 } else {
27 queue = new RequestQueue(new DiskBasedCache(cacheDir, maxDiskCacheBytes), network);
28 }
29
30 queue.start();
31 return queue;
32 }
在这里,咱们看到了一个版本判断,是否是瞬间感受有点熟悉,没错,咱们前面说的,volley2.3以前用的是HTTPClient,2.3以后使用的是HttpURLConnection
就是在这里进行判断的。接着看queue.start();
1 public void start() {
2 this.stop();
3 this.mCacheDispatcher = new CacheDispatcher(this.mCacheQueue, this.mNetworkQueue, this.mCache, this.mDelivery);
4 this.mCacheDispatcher.start();
5
6 for(int i = 0; i < this.mDispatchers.length; ++i) {
7 NetworkDispatcher networkDispatcher = new NetworkDispatcher(this.mNetworkQueue, this.mNetwork, this.mCache, this.mDelivery);
8 this.mDispatchers[i] = networkDispatcher;
9 networkDispatcher.start();
10 }
11
12 }
mCacheDispatcher是缓存调度线程,NetworkDispatcher是网络调度线程,而这个this.mDispatchers.length系统默认的大小为4,也就是说,在这里总共启动了5个线程在后台运行。
好了,到这里,就能够了,看源码不要每一行都弄懂,否则,出不来了。到这里就拿到了这个RequestQueue对象。回过头来看前面使用的代码
1 //获取volley的请求对象
2 RequestQueue requestQueue = Volley.newRequestQueue(getApplicationContext());
3 StringRequest stringRequest = new StringRequest(StringRequest.Method.GET, "http://www.baidu.com", new Response.Listener<String>() {
4 @Override
5 public void onResponse(String s) {
6 Log.d("MainActivity", "----->" + s);
7
8 }
9 }, new Response.ErrorListener() {
10 @Override
11 public void onErrorResponse(VolleyError volleyError) {
12 Log.d("MainActivity", "---volleyError-->" + volleyError);
13 }
14 });
15 requestQueue.add(stringRequest);
咱们拿到这个RequestQueue对象之后,而后就把这个请求经过add方法添加到队列中,咱们看看这个add()方法是怎么执行的。
1 public <T> Request<T> add(Request<T> request) {
2 request.setRequestQueue(this);
3 Set var2 = this.mCurrentRequests;
4 synchronized(this.mCurrentRequests) {
5 this.mCurrentRequests.add(request);
6 }
7
8 request.setSequence(this.getSequenceNumber());
9 request.addMarker("add-to-queue");
10 if (!request.shouldCache()) { //若是不能缓存
11 this.mNetworkQueue.add(request);
12 return request;
13 } else {
14 Map var7 = this.mWaitingRequests;
15 synchronized(this.mWaitingRequests) {
16 String cacheKey = request.getCacheKey();
17 if (this.mWaitingRequests.containsKey(cacheKey)) { //判断以前是否执行过,可是尚未返回结果
18 Queue<Request<?>> stagedRequests = (Queue)this.mWaitingRequests.get(cacheKey);
19 if (stagedRequests == null) {
20 stagedRequests = new LinkedList();
21 }
22
23 ((Queue)stagedRequests).add(request);
24 this.mWaitingRequests.put(cacheKey, stagedRequests);
25 if (VolleyLog.DEBUG) {
26 VolleyLog.v("Request for cacheKey=%s is in flight, putting on hold.", new Object[]{cacheKey});
27 }
28 } else {
29 //没有的话就将请求加入缓存队列mCacheQueue,同时加入mWaitingRequests中用来作下次一样请求来时的重复判断依据
30 this.mWaitingRequests.put(cacheKey, (Object)null);
31 this.mCacheQueue.add(request);
32 }
33
34 return request;
35 }
36 }
37 }
从代码中能够看出,首先判断是否能够缓存,固然,默认是能够缓存的。若是不能缓存的话,则经过this.mNetworkQueue.add(request);将请求添加到网络请求队列中。若是能够缓存
则还会判断一次这个请求是否请求,若是执行过就就经过this.mWaitingRequests.put(cacheKey, stagedRequests);添加到mWaitingRequests队列,不在重复请求。不然就加入到缓存队列。
大致的流程是这样。如今咱们看看缓存的,和网络的是怎么执行的。咱们找到start()方法
1 public void start() {
2 this.stop();
3 this.mCacheDispatcher = new CacheDispatcher(this.mCacheQueue, this.mNetworkQueue, this.mCache, this.mDelivery);
4 this.mCacheDispatcher.start();
5
6 for(int i = 0; i < this.mDispatchers.length; ++i) {
7 NetworkDispatcher networkDispatcher = new NetworkDispatcher(this.mNetworkQueue, this.mNetwork, this.mCache, this.mDelivery);
8 this.mDispatchers[i] = networkDispatcher;
9 networkDispatcher.start();
10 }
11
12 }
先看CacheDispatcher,找到run()方法
1 public void run() {
2 if (DEBUG) {
3 VolleyLog.v("start new dispatcher", new Object[0]);
4 }
5
6 Process.setThreadPriority(10);
7 this.mCache.initialize();
8
9 while(true) {
10 while(true) {
11 while(true) {
12 while(true) {
13 try {
14 while(true) {
15 final Request<?> request = (Request)this.mCacheQueue.take(); //从缓存队列中获取到一个请求
16 request.addMarker("cache-queue-take");
17 if (request.isCanceled()) { //判断请求是否取消,若是取消了,那就将该请求finish掉
18 request.finish("cache-discard-canceled");
19 } else {
20 Entry entry = this.mCache.get(request.getCacheKey());
21 if (entry == null) {//若是从缓存中取出来的内容为空,则将请求加入到网络线程中再次请求
22 request.addMarker("cache-miss");
23 this.mNetworkQueue.put(request);
24 } else if (entry.isExpired()) { //若是请求过时了,则将请求加入到网络线程中再次请求
25 request.addMarker("cache-hit-expired");
26 request.setCacheEntry(entry);
27 this.mNetworkQueue.put(request);
28 } else { //将数据回调到主线程
29 request.addMarker("cache-hit");
30 Response<?> response = request.parseNetworkResponse(new NetworkResponse(entry.data, entry.responseHeaders));
31 request.addMarker("cache-hit-parsed");
32 if (entry.refreshNeeded()) {
33 request.addMarker("cache-hit-refresh-needed");
34 request.setCacheEntry(entry);
35 response.intermediate = true;
36 this.mDelivery.postResponse(request, response, new Runnable() {
37 public void run() {
38 try {
39 CacheDispatcher.this.mNetworkQueue.put(request);
40 } catch (InterruptedException var2) {
41 ;
42 }
43
44 }
45 });
46 } else {
47 this.mDelivery.postResponse(request, response);
48 }
49 }
50 }
51 }
52 } catch (InterruptedException var4) {
53 if (this.mQuit) {
54 return;
55 }
56 }
57 }
58 }
59 }
60 }
61 }
这里嵌套了几个循环,有点凌乱啊,可是慢慢分析的话,就会发现,其实很清晰。我在注释上面写了,这里就不重复了
咱们在看看NetworkDispatcher,看看网络线程是怎么执行的。同样找到run()方法
1 public void run() {
2 Process.setThreadPriority(10);
3
4 while(true) {
5 long startTimeMs;
6 Request request;
7 while(true) {
8 startTimeMs = SystemClock.elapsedRealtime();
9
10 try {
11 request = (Request)this.mQueue.take(); //获取到一个请求
12 break;
13 } catch (InterruptedException var6) {
14 if (this.mQuit) {
15 return;
16 }
17 }
18 }
19
20 try {
21 request.addMarker("network-queue-take");
22 if (request.isCanceled()) { //若是请求取消了,则将请求finish掉
23 request.finish("network-discard-cancelled");
24 } else {//进行网络请求
25 this.addTrafficStatsTag(request);
26 NetworkResponse networkResponse = this.mNetwork.performRequest(request);
27 request.addMarker("network-http-complete");
28 if (networkResponse.notModified && request.hasHadResponseDelivered()) {
29 request.finish("not-modified");
30 } else {
31 Response<?> response = request.parseNetworkResponse(networkResponse);
32 request.addMarker("network-parse-complete");
33 if (request.shouldCache() && response.cacheEntry != null) {
34 this.mCache.put(request.getCacheKey(), response.cacheEntry);
35 request.addMarker("network-cache-written");
36 }
37
38 request.markDelivered();
39 this.mDelivery.postResponse(request, response);
40 }
41 }
42 } catch (VolleyError var7) {
43 var7.setNetworkTimeMs(SystemClock.elapsedRealtime() - startTimeMs);
44 this.parseAndDeliverNetworkError(request, var7);
45 } catch (Exception var8) {
46 VolleyLog.e(var8, "Unhandled exception %s", new Object[]{var8.toString()});
47 VolleyError volleyError = new VolleyError(var8);
48 volleyError.setNetworkTimeMs(SystemClock.elapsedRealtime() - startTimeMs);
49 this.mDelivery.postError(request, volleyError);
50 }
51 }
52 }
代码比较多,咱们直接找到NetworkResponse networkResponse = this.mNetwork.performRequest(request);这句代码,这句代码就是请求网络的代码,最核心的。performRequest是一个接口,咱们看看这个
performRequest()方法。Network在最开始说版本判断的时候里面有一句代码Network network = new BasicNetwork((HttpStack)stack); 从这句代码,咱们能够知道BasicNetwork才是最终
实现网络请求的类,咱们找到performRequest方法
1 public NetworkResponse performRequest(Request<?> request) throws VolleyError {
2 long requestStart = SystemClock.elapsedRealtime();
3
4 while(true) {
5 HttpResponse httpResponse = null;
6 byte[] responseContents = null;
7 Map responseHeaders = Collections.emptyMap();
8
9 try {
10 Map<String, String> headers = new HashMap();
11 this.addCacheHeaders(headers, request.getCacheEntry());
12 httpResponse = this.mHttpStack.performRequest(request, headers);
13 StatusLine statusLine = httpResponse.getStatusLine();
14 int statusCode = statusLine.getStatusCode();
15 responseHeaders = convertHeaders(httpResponse.getAllHeaders());
16 if (statusCode == 304) {
17 Entry entry = request.getCacheEntry();
18 if (entry == null) {
19 return new NetworkResponse(304, (byte[])null, responseHeaders, true, SystemClock.elapsedRealtime() - requestStart);
20 }
21
22 entry.responseHeaders.putAll(responseHeaders);
23 return new NetworkResponse(304, entry.data, entry.responseHeaders, true, SystemClock.elapsedRealtime() - requestStart);
24 }
25
26 if (statusCode == 301 || statusCode == 302) {
27 String newUrl = (String)responseHeaders.get("Location");
28 request.setRedirectUrl(newUrl);
29 }
30
31 byte[] responseContents;
32 if (httpResponse.getEntity() != null) {
33 responseContents = this.entityToBytes(httpResponse.getEntity());
34 } else {
35 responseContents = new byte[0];
36 }
37
38 long requestLifetime = SystemClock.elapsedRealtime() - requestStart;
39 this.logSlowRequests(requestLifetime, request, responseContents, statusLine);
40 if (statusCode >= 200 && statusCode <= 299) {
41 return new NetworkResponse(statusCode, responseContents, responseHeaders, false, SystemClock.elapsedRealtime() - requestStart);
42 }
43
44 throw new IOException();
45 } catch (SocketTimeoutException var12) {
46 attemptRetryOnException("socket", request, new TimeoutError());
47 } catch (ConnectTimeoutException var13) {
48 attemptRetryOnException("connection", request, new TimeoutError());
49 } catch (MalformedURLException var14) {
50 throw new RuntimeException("Bad URL " + request.getUrl(), var14);
51 } catch (IOException var15) {
52 int statusCode = false;
53 NetworkResponse networkResponse = null;
54 if (httpResponse == null) {
55 throw new NoConnectionError(var15);
56 }
57
58 int statusCode = httpResponse.getStatusLine().getStatusCode();
59 if (statusCode != 301 && statusCode != 302) {
60 VolleyLog.e("Unexpected response code %d for %s", new Object[]{statusCode, request.getUrl()});
61 } else {
62 VolleyLog.e("Request at %s has been redirected to %s", new Object[]{request.getOriginUrl(), request.getUrl()});
63 }
64
65 if (responseContents == null) {
66 throw new NetworkError(networkResponse);
67 }
68
69 networkResponse = new NetworkResponse(statusCode, (byte[])responseContents, responseHeaders, false, SystemClock.elapsedRealtime() - requestStart);
70 if (statusCode != 401 && statusCode != 403) {
71 if (statusCode != 301 && statusCode != 302) {
72 throw new ServerError(networkResponse);
73 }
74
75 attemptRetryOnException("redirect", request, new AuthFailureError(networkResponse));
76 } else {
77 attemptRetryOnException("auth", request, new AuthFailureError(networkResponse));
78 }
79 }
80 }
81 }
代码比较多,可是大多数代码是判断状态返回码的,不须要理会。咱们直接看httpResponse = this.mHttpStack.performRequest(request, headers);这一句代码,HttpStack这个有没有很熟悉。没有??不要紧我在复制一次代码
1 if (stack == null) {
2 if (VERSION.SDK_INT >= 9) {
3 stack = new HurlStack();
4 } else {
5 stack = new HttpClientStack(AndroidHttpClient.newInstance(userAgent));
6 }
7 }
仍是在这个版本判断这里,这里就是HurlStack就是真正的网络请求的类了,网络请求,就是写在这个类里面的。好了,volley整个流程大概就是这样了。
复制代码