你們都知道谷歌如今已經不維護volley框架,爲何如今還要分析volley源碼呢。html
首先,volley框架的設計思想是很是值得借鑑,翻下當下我的開源 的一些網絡框架,不少都是借鑑的volley的設計思想完成的。android
另外,volley 源碼相對簡單易懂。json
1、首先volley使用不一樣請求模式須要new一個相應的request對象緩存
以stringrequest爲例:網絡
1 public void testVolley() { 2 RequestQueue requestQueue = Volley.newRequestQueue(this);//建立一個隊列 3 StringRequest stringRequest = new StringRequest("", new Response.Listener<String>() { 4 @Override 5 public void onResponse(String response) { 6 7 } 8 }, new Response.ErrorListener() { 9 @Override 10 public void onErrorResponse(VolleyError error) { 11 12 } 13 }); 14 requestQueue.add(stringRequest);//把1請求添加進隊列 15 16 }
同理須要json串的請求,則new出一個JsonRequest 圖片則new出 ImageRequest 這是標準的策略模式。方便擴展,好比咱們後期須要請求自定義的數據格式,就能夠繼承request這個類,比照stringrequest寫出本身的request來完成網絡數據的獲取和解析。app
具體使用代碼就不寫了。框架
2、源碼分析ide
1 public static RequestQueue newRequestQueue(Context context, HttpStack stack) { 2 File cacheDir = new File(context.getCacheDir(), DEFAULT_CACHE_DIR); 3 4 String userAgent = "volley/0"; 5 try { 6 String packageName = context.getPackageName(); 7 PackageInfo info = context.getPackageManager().getPackageInfo(packageName, 0); 8 userAgent = packageName + "/" + info.versionCode; 9 } catch (NameNotFoundException e) { 10 } 11 12 if (stack == null) { 13 if (Build.VERSION.SDK_INT >= 9) { 14 stack = new HurlStack(); 15 } else { 16 // Prior to Gingerbread, HttpUrlConnection was unreliable. 17 // See: http://android-developers.blogspot.com/2011/09/androids-http-clients.html 18 stack = new HttpClientStack(AndroidHttpClient.newInstance(userAgent)); 19 } 20 } 21 22 Network network = new BasicNetwork(stack); 23 24 RequestQueue queue = new RequestQueue(new DiskBasedCache(cacheDir), network); 25 queue.start(); 26 27 return queue; 28 }
一、建立一個請求隊列會調用Volley類中的 newRequestQueue方法。咱們主要看第2四、25行(標紅)建立後調用了 queue的start方法源碼分析
1 public void start() { 2 stop(); // Make sure any currently running dispatchers are stopped. 3 // Create the cache dispatcher and start it. 4 mCacheDispatcher = new CacheDispatcher(mCacheQueue, mNetworkQueue, mCache, mDelivery); 5 mCacheDispatcher.start(); 6 7 // Create network dispatchers (and corresponding threads) up to the pool size. 8 for (int i = 0; i < mDispatchers.length; i++) { 9 NetworkDispatcher networkDispatcher = new NetworkDispatcher(mNetworkQueue, mNetwork, 10 mCache, mDelivery); 11 mDispatchers[i] = networkDispatcher; 12 networkDispatcher.start(); 13 } 14 }
二、建立一個緩存線程四、5行和四個網絡請求線程8--12行。(mDispatchers.length默認值爲4)並 調用他們的start()方法post
CacheDispatcher和NetworkDispatcher都是繼承於 Thead類的。start的方法就是啓動該線程
三、你們都熟悉thread的用法,調用start後確定是執行run方法咱們接下來看看NetworkDispatcher的run方法作了什麼
1 @Override 2 public void run() { 3 Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND); 4 while (true) { 5 long startTimeMs = SystemClock.elapsedRealtime(); 6 Request<?> request; 7 try { 8 // Take a request from the queue. 9 request = mQueue.take(); 10 } catch (InterruptedException e) { 11 // We may have been interrupted because it was time to quit. 12 if (mQuit) { 13 return; 14 } 15 continue; 16 } 17 18 try { 19 request.addMarker("network-queue-take"); 20 21 // If the request was cancelled already, do not perform the 22 // network request. 23 if (request.isCanceled()) { 24 request.finish("network-discard-cancelled"); 25 continue; 26 } 27 28 addTrafficStatsTag(request); 29 30 // Perform the network request. 31 NetworkResponse networkResponse = mNetwork.performRequest(request); 32 request.addMarker("network-http-complete"); 33 34 // If the server returned 304 AND we delivered a response already, 35 // we're done -- don't deliver a second identical response. 36 if (networkResponse.notModified && request.hasHadResponseDelivered()) { 37 request.finish("not-modified"); 38 continue; 39 } 40 41 // Parse the response here on the worker thread. 42 Response<?> response = request.parseNetworkResponse(networkResponse); 43 request.addMarker("network-parse-complete"); 44 45 // Write to cache if applicable. 46 // TODO: Only update cache metadata instead of entire record for 304s. 47 if (request.shouldCache() && response.cacheEntry != null) { 48 mCache.put(request.getCacheKey(), response.cacheEntry); 49 request.addMarker("network-cache-written"); 50 } 51 52 // Post the response back. 53 request.markDelivered(); 54 mDelivery.postResponse(request, response); 55 } catch (VolleyError volleyError) { 56 volleyError.setNetworkTimeMs(SystemClock.elapsedRealtime() - startTimeMs); 57 parseAndDeliverNetworkError(request, volleyError); 58 } catch (Exception e) { 59 VolleyLog.e(e, "Unhandled exception %s", e.toString()); 60 VolleyError volleyError = new VolleyError(e); 61 volleyError.setNetworkTimeMs(SystemClock.elapsedRealtime() - startTimeMs); 62 mDelivery.postError(request, volleyError); 63 } 64 } 65 }
第四行是一個while(true)循環。說明該方法是一直在執行。主要邏輯是從requestQueue中不斷取出網絡任務去執行。二queue中的任務就是在咱們使用volley時的最後一行代碼 requestQueue.add(stringRequest);//把1請求添加進隊列
看到此處你們就須要明白,爲何volley官方明確要求 咱們全部的網絡請求使用同一個 requestQueue,而不是每次都new出來。
由於new出一個requestQueue後,隊裏中會默認有5個線程在一直等待任務的加入。咱們只須要每次把新的請求 add進去便可 requestQueue.add(stringRequest);
若是每次都new出一個queue會浪費大量資源。
本篇總結:
一、new出一個隊列 requestQueue
二、new出一個合適的request
三、把request加入(add)到隊列中去執行
四、requestQueue 只建議new一次,也就是在app中,只維護一個requestqueue,以後的網絡請求都是往此隊列中添加request便可。
五、requestQueue 默認是5個線程,緩存一個,網絡請求4個,能夠根據本身需求添加或減小。