Volley拓展框架——Netroid,以及與Volley的差異
轉自:http://blog.csdn.net/brian512/article/details/50499423?ref=myread
Netroid是一個基於Volley實現的Android Http庫。提供執行網路請求、快取返回結果、批量圖片載入、大檔案斷點下載的常見Http互動功能。致力於避免每個專案重複開發基礎Http功能,實現顯著地縮短開發週期的願景。
功能上的區別:
作為Volley的拓展框架,netroid增加了大檔案斷點下載,並且netroid的可定製性更強。
實現上的區別:
1. 快取的處理;
在volley中,快取的過期時間是通過 ttl 和 softTtl 控制
<code class="hljs java has-numbering"> <span class="hljs-javadoc">/** True if the entry is expired. */</span> <span class="hljs-keyword">public</span> <span class="hljs-keyword">boolean</span> <span class="hljs-title">isExpired</span>() { <span class="hljs-keyword">return</span> <span class="hljs-keyword">this</span>.ttl < System.currentTimeMillis(); } <span class="hljs-javadoc">/** True if a refresh is needed from the original data source. */</span> <span class="hljs-keyword">public</span> <span class="hljs-keyword">boolean</span> <span class="hljs-title">refreshNeeded</span>() { <span class="hljs-keyword">return</span> <span class="hljs-keyword">this</span>.softTtl < System.currentTimeMillis(); }</code><ul class="pre-numbering"><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li></ul><ul class="pre-numbering"><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li></ul>
而這兩個值的來源是HttpHeaderParser.parseCacheHeaders
<code class="hljs cs has-numbering"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> Cache.Entry <span class="hljs-title">parseCacheHeaders</span>(NetworkResponse response) { <span class="hljs-keyword">long</span> now = System.currentTimeMillis(); <span class="hljs-keyword">long</span> serverDate = <span class="hljs-number">0</span>; <span class="hljs-keyword">long</span> lastModified = <span class="hljs-number">0</span>; <span class="hljs-keyword">long</span> serverExpires = <span class="hljs-number">0</span>; <span class="hljs-keyword">long</span> softExpire = <span class="hljs-number">0</span>; <span class="hljs-keyword">long</span> finalExpire = <span class="hljs-number">0</span>; <span class="hljs-keyword">long</span> maxAge = <span class="hljs-number">0</span>; <span class="hljs-keyword">long</span> staleWhileRevalidate = <span class="hljs-number">0</span>; boolean hasCacheControl = <span class="hljs-keyword">false</span>; boolean mustRevalidate = <span class="hljs-keyword">false</span>; String serverEtag = <span class="hljs-keyword">null</span>; headerValue = headers.<span class="hljs-keyword">get</span>(<span class="hljs-string">"Date"</span>); <span class="hljs-keyword">if</span> (headerValue != <span class="hljs-keyword">null</span>) { serverDate = parseDateAsEpoch(headerValue); } headerValue = headers.<span class="hljs-keyword">get</span>(<span class="hljs-string">"Cache-Control"</span>); <span class="hljs-keyword">if</span> (headerValue != <span class="hljs-keyword">null</span>) { hasCacheControl = <span class="hljs-keyword">true</span>; String[] tokens = headerValue.split(<span class="hljs-string">","</span>); <span class="hljs-keyword">for</span> (<span class="hljs-keyword">int</span> i = <span class="hljs-number">0</span>; i < tokens.length; i++) { String token = tokens[i].trim(); <span class="hljs-keyword">if</span> (token.equals(<span class="hljs-string">"no-cache"</span>) || token.equals(<span class="hljs-string">"no-store"</span>)) { <span class="hljs-keyword">return</span> <span class="hljs-keyword">null</span>; } <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (token.startsWith(<span class="hljs-string">"max-age="</span>)) { <span class="hljs-keyword">try</span> { maxAge = Long.parseLong(token.substring(<span class="hljs-number">8</span>)); } <span class="hljs-keyword">catch</span> (Exception e) { } } <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (token.startsWith(<span class="hljs-string">"stale-while-revalidate="</span>)) { <span class="hljs-keyword">try</span> { staleWhileRevalidate = Long.parseLong(token.substring(<span class="hljs-number">23</span>)); } <span class="hljs-keyword">catch</span> (Exception e) { } } <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (token.equals(<span class="hljs-string">"must-revalidate"</span>) || token.equals(<span class="hljs-string">"proxy-revalidate"</span>)) { mustRevalidate = <span class="hljs-keyword">true</span>; } } } headerValue = headers.<span class="hljs-keyword">get</span>(<span class="hljs-string">"Expires"</span>); <span class="hljs-keyword">if</span> (headerValue != <span class="hljs-keyword">null</span>) { serverExpires = parseDateAsEpoch(headerValue); } headerValue = headers.<span class="hljs-keyword">get</span>(<span class="hljs-string">"Last-Modified"</span>); <span class="hljs-keyword">if</span> (headerValue != <span class="hljs-keyword">null</span>) { lastModified = parseDateAsEpoch(headerValue); <span class="hljs-comment">// Cache-Control takes precedence over an Expires header, even if both exist and Expires is more restrictive.</span> <span class="hljs-comment">// 如果伺服器返回的header中有Cache-Control欄位,則可以按照制定的規則進行設定</span> <span class="hljs-keyword">if</span> (hasCacheControl) { softExpire = now + maxAge * <span class="hljs-number">1000</span>; finalExpire = mustRevalidate ? softExpire : softExpire + staleWhileRevalidate * <span class="hljs-number">1000</span>; } <span class="hljs-comment">// 若伺服器返回的header中包含Expires和Date欄位</span> <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (serverDate > <span class="hljs-number">0</span> && serverExpires >= serverDate) { <span class="hljs-comment">// Default semantic for Expire header in HTTP specification is softExpire.</span> softExpire = now + (serverExpires - serverDate); finalExpire = softExpire; } Cache.Entry entry = <span class="hljs-keyword">new</span> Cache.Entry(); entry.data = response.data; entry.etag = serverEtag; entry.softTtl = softExpire; entry.ttl = finalExpire; entry.serverDate = serverDate; entry.lastModified = lastModified; <span class="hljs-keyword">return</span> entry; }</code><ul class="pre-numbering"><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li><li>10</li><li>11</li><li>12</li><li>13</li><li>14</li><li>15</li><li>16</li><li>17</li><li>18</li><li>19</li><li>20</li><li>21</li><li>22</li><li>23</li><li>24</li><li>25</li><li>26</li><li>27</li><li>28</li><li>29</li><li>30</li><li>31</li><li>32</li><li>33</li><li>34</li><li>35</li><li>36</li><li>37</li><li>38</li><li>39</li><li>40</li><li>41</li><li>42</li><li>43</li><li>44</li><li>45</li><li>46</li><li>47</li><li>48</li><li>49</li><li>50</li><li>51</li><li>52</li><li>53</li><li>54</li><li>55</li><li>56</li><li>57</li><li>58</li><li>59</li><li>60</li><li>61</li><li>62</li><li>63</li><li>64</li><li>65</li><li>66</li><li>67</li><li>68</li></ul><ul class="pre-numbering"><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li><li>10</li><li>11</li><li>12</li><li>13</li><li>14</li><li>15</li><li>16</li><li>17</li><li>18</li><li>19</li><li>20</li><li>21</li><li>22</li><li>23</li><li>24</li><li>25</li><li>26</li><li>27</li><li>28</li><li>29</li><li>30</li><li>31</li><li>32</li><li>33</li><li>34</li><li>35</li><li>36</li><li>37</li><li>38</li><li>39</li><li>40</li><li>41</li><li>42</li><li>43</li><li>44</li><li>45</li><li>46</li><li>47</li><li>48</li><li>49</li><li>50</li><li>51</li><li>52</li><li>53</li><li>54</li><li>55</li><li>56</li><li>57</li><li>58</li><li>59</li><li>60</li><li>61</li><li>62</li><li>63</li><li>64</li><li>65</li><li>66</li><li>67</li><li>68</li></ul>
根據上述程式碼中的中文註釋看,若伺服器返回的header中沒有Cache-Control,Expires,Date等欄位,則 ttl 和 softExpire 的值均為預設的0,從而使得快取永遠是過期的,其影響是快取不僅不能起效,反而每次網路請求都需要更新快取,最後就是拖累整體效能。
為此,netroid採用expireTime欄位替代了 ttl 和 softExpire ,每次發起請求時,需指定過期時間
<code class="hljs java has-numbering"> <span class="hljs-comment">// com.duowan.mobile.netroid.Request.java</span> <span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">setCacheExpireTime</span>(TimeUnit timeUnit, <span class="hljs-keyword">int</span> amount) { <span class="hljs-keyword">this</span>.mCacheExpireTime = System.currentTimeMillis() + timeUnit.toMillis(amount); } <span class="hljs-keyword">public</span> <span class="hljs-keyword">final</span> <span class="hljs-keyword">boolean</span> <span class="hljs-title">shouldCache</span>() { <span class="hljs-keyword">return</span> mCacheExpireTime > <span class="hljs-number">0</span>; }</code><ul class="pre-numbering"><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li></ul><ul class="pre-numbering"><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li></ul>
從上述程式碼看出,若沒有設定過期時間時,不會產生快取
<code class="hljs java has-numbering"> <span class="hljs-javadoc">/** True if the entry is expired. */</span> <span class="hljs-keyword">public</span> <span class="hljs-keyword">boolean</span> <span class="hljs-title">isExpired</span>() { <span class="hljs-keyword">return</span> expireTime < System.currentTimeMillis(); } <span class="hljs-javadoc">/** True if a refresh is needed from the original data source. */</span> <span class="hljs-keyword">public</span> <span class="hljs-keyword">boolean</span> <span class="hljs-title">refreshNeeded</span>() { <span class="hljs-comment">// still unimplemented, might be use a constant like 'refreshTime'?</span> <span class="hljs-keyword">return</span> <span class="hljs-keyword">this</span>.expireTime < System.currentTimeMillis(); }</code><ul class="pre-numbering"><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li><li>10</li></ul><ul class="pre-numbering"><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li><li>10</li></ul>
2. 網路資料處理;
首先貼一段帶註釋的程式碼:
<code class="hljs java has-numbering"> <span class="hljs-keyword">public</span> NetworkResponse <span class="hljs-title">performRequest</span>(Request<?> request) <span class="hljs-keyword">throws</span> VolleyError { <span class="hljs-comment">// Determine if request had non-http perform.</span> <span class="hljs-comment">// 若該請求不需要訪問網路,則直接複寫perform方法。使用場景如,載入資料庫的資料,或者載入本地圖片,使用此框架可以統一處理此類耗時操作</span> NetworkResponse networkResponse = request.perform(); <span class="hljs-keyword">if</span> (networkResponse != <span class="hljs-keyword">null</span>) <span class="hljs-keyword">return</span> networkResponse; <span class="hljs-keyword">long</span> requestStart = SystemClock.elapsedRealtime(); <span class="hljs-keyword">while</span> (<span class="hljs-keyword">true</span>) { <span class="hljs-comment">// If the request was cancelled already,</span> <span class="hljs-comment">// do not perform the network request.</span> <span class="hljs-keyword">if</span> (request.isCanceled()) { request.finish(<span class="hljs-string">"perform-discard-cancelled"</span>); mDelivery.postCancel(request); <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> NetworkError(networkResponse); } HttpResponse httpResponse = <span class="hljs-keyword">null</span>; <span class="hljs-keyword">byte</span>[] responseContents = <span class="hljs-keyword">null</span>; <span class="hljs-keyword">try</span> { <span class="hljs-comment">// prepare to perform this request, normally is reset the request headers.</span> <span class="hljs-comment">// 此方法預設實現為空,若請求有需要預處理的話,該設計也是極好的。使用場景如,在進行大檔案斷點下載時,需要設定Range頭欄位,但是網路異常進行retry時就不太好處理range了,但是有這個方法就很簡單了</span> request.prepare(); httpResponse = mHttpStack.performRequest(request); StatusLine statusLine = httpResponse.getStatusLine(); <span class="hljs-keyword">int</span> statusCode = statusLine.getStatusCode(); <span class="hljs-keyword">if</span> (statusCode < <span class="hljs-number">200</span> || statusCode > <span class="hljs-number">299</span>) <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> IOException(); <span class="hljs-comment">// 此方法的預設實現為volley的實現方法,但是可以複寫該方法。volley的實現方式是直接把請求到的資料轉為byte[],此方式會限制請求的資料量不能太大,否則會OOM。</span> <span class="hljs-comment">// 若下載大檔案時,就得複寫這個方法,將網路請求的資料流讀寫到檔案,而不是記憶體</span> responseContents = request.handleResponse(httpResponse, mDelivery); <span class="hljs-comment">// if the request is slow, log it.</span> <span class="hljs-keyword">long</span> requestLifetime = SystemClock.elapsedRealtime() - requestStart; logSlowRequests(requestLifetime, request, responseContents, statusLine); <span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> NetworkResponse(statusCode, responseContents, parseCharset(httpResponse)); } <span class="hljs-keyword">catch</span> (SocketTimeoutException e) { attemptRetryOnException(<span class="hljs-string">"socket"</span>, request, <span class="hljs-keyword">new</span> TimeoutError()); } <span class="hljs-keyword">catch</span> (ConnectTimeoutException e) { attemptRetryOnException(<span class="hljs-string">"connection"</span>, request, <span class="hljs-keyword">new</span> TimeoutError()); } <span class="hljs-keyword">catch</span> (MalformedURLException e) { <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> RuntimeException(<span class="hljs-string">"Bad URL "</span> + request.getUrl(), e); } <span class="hljs-keyword">catch</span> (IOException e) { 。。。 } } }</code><ul class="pre-numbering"><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li><li>10</li><li>11</li><li>12</li><li>13</li><li>14</li><li>15</li><li>16</li><li>17</li><li>18</li><li>19</li><li>20</li><li>21</li><li>22</li><li>23</li><li>24</li><li>25</li><li>26</li><li>27</li><li>28</li><li>29</li><li>30</li><li>31</li><li>32</li><li>33</li><li>34</li><li>35</li><li>36</li><li>37</li><li>38</li><li>39</li><li>40</li><li>41</li><li>42</li><li>43</li><li>44</li><li>45</li><li>46</li><li>47</li><li>48</li><li>49</li><li>50</li></ul><ul class="pre-numbering"><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li><li>10</li><li>11</li><li>12</li><li>13</li><li>14</li><li>15</li><li>16</li><li>17</li><li>18</li><li>19</li><li>20</li><li>21</li><li>22</li><li>23</li><li>24</li><li>25</li><li>26</li><li>27</li><li>28</li><li>29</li><li>30</li><li>31</li><li>32</li><li>33</li><li>34</li><li>35</li><li>36</li><li>37</li><li>38</li><li>39</li><li>40</li><li>41</li><li>42</li><li>43</li><li>44</li><li>45</li><li>46</li><li>47</li><li>48</li><li>49</li><li>50</li></ul>
3. 資料請求過程回撥;
在volley的實現中,是通過ExecutorDelivery將資料請求的結果回撥給呼叫者。
<code class="hljs java has-numbering"><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">interface</span> <span class="hljs-title">ResponseDelivery</span> {</span> <span class="hljs-javadoc">/** * Parses a response from the network or cache and delivers it. */</span> <span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">postResponse</span>(Request<?> request, Response<?> response); <span class="hljs-javadoc">/** * Parses a response from the network or cache and delivers it. The provided * Runnable will be executed after delivery. */</span> <span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">postResponse</span>(Request<?> request, Response<?> response, Runnable runnable); <span class="hljs-javadoc">/** * Posts an error for the given request. */</span> <span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">postError</span>(Request<?> request, VolleyError error); } </code><ul class="pre-numbering"><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li><li>10</li><li>11</li><li>12</li><li>13</li><li>14</li><li>15</li><li>16</li><li>17</li><li>18</li></ul><ul class="pre-numbering"><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li><li>10</li><li>11</li><li>12</li><li>13</li><li>14</li><li>15</li><li>16</li><li>17</li><li>18</li></ul>
netroid在此基礎上增加了一些回撥:
<code class="hljs java has-numbering"><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">interface</span> <span class="hljs-title">Delivery</span> {</span> <span class="hljs-javadoc">/** Posts request finished callback for the given request. */</span> <span class="hljs-keyword">void</span> postFinish(Request<?> request); <span class="hljs-javadoc">/** Parses a response from the network or cache and delivers it. */</span> <span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">postResponse</span>(Request<?> request, Response<?> response); <span class="hljs-javadoc">/** * Parses a response from the network or cache and delivers it. The provided * Runnable will be executed after delivery. */</span> <span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">postResponse</span>(Request<?> request, Response<?> response, Runnable runnable); <span class="hljs-javadoc">/** Posts an error for the given request. */</span> <span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">postError</span>(Request<?> request, VolleyError error); <span class="hljs-javadoc">/** Posts a cancel callback for the given request. */</span> <span class="hljs-keyword">void</span> postCancel(Request<?> request); <span class="hljs-javadoc">/** Posts starting execute callback for the given request. */</span> <span class="hljs-keyword">void</span> postPreExecute(Request<?> request); <span class="hljs-javadoc">/** Posts cache used callback for the given request. */</span> <span class="hljs-keyword">void</span> postUsedCache(Request<?> request); <span class="hljs-javadoc">/** Posts networking callback for the given request. */</span> <span class="hljs-keyword">void</span> postNetworking(Request<?> request); <span class="hljs-javadoc">/** Posts request retry callback for the given request. */</span> <span class="hljs-keyword">void</span> postRetry(Request<?> request); <span class="hljs-javadoc">/** Posts file download progress stat. */</span> <span class="hljs-keyword">void</span> postDownloadProgress(Request<?> request, <span class="hljs-keyword">long</span> fileSize, <span class="hljs-keyword">long</span> downloadedSize); }</code><ul class="pre-numbering"><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li><li>10</li><li>11</li><li>12</li><li>13</li><li>14</li><li>15</li><li>16</li><li>17</li><li>18</li><li>19</li><li>20</li><li>21</li><li>22</li><li>23</li><li>24</li><li>25</li><li>26</li><li>27</li><li>28</li><li>29</li><li>30</li><li>31</li><li>32</li><li>33</li><li>34</li><li>35</li></ul><ul class="pre-numbering"><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li><li>10</li><li>11</li><li>12</li><li>13</li><li>14</li><li>15</li><li>16</li><li>17</li><li>18</li><li>19</li><li>20</li><li>21</li><li>22</li><li>23</li><li>24</li><li>25</li><li>26</li><li>27</li><li>28</li><li>29</li><li>30</li><li>31</li><li>32</li><li>33</li><li>34</li><li>35</li></ul>
可以看出,這些回撥基本覆蓋了請求過程中的關鍵點,主要是有postDownloadProgress方法,進行回撥檔案下載進度。
<code class="hljs avrasm has-numbering"> // <span class="hljs-keyword">com</span><span class="hljs-preprocessor">.duowan</span><span class="hljs-preprocessor">.mobile</span><span class="hljs-preprocessor">.netroid</span><span class="hljs-preprocessor">.NetworkDispatcher</span><span class="hljs-preprocessor">.java</span> request<span class="hljs-preprocessor">.addMarker</span>(<span class="hljs-string">"network-queue-take"</span>)<span class="hljs-comment">;</span> mDelivery<span class="hljs-preprocessor">.postPreExecute</span>(request)<span class="hljs-comment">;</span> // If the request was cancelled already, // do not perform the network request. if (request<span class="hljs-preprocessor">.isCanceled</span>()) { request<span class="hljs-preprocessor">.finish</span>(<span class="hljs-string">"network-discard-cancelled"</span>)<span class="hljs-comment">;</span> mDelivery<span class="hljs-preprocessor">.postCancel</span>(request)<span class="hljs-comment">;</span> mDelivery<span class="hljs-preprocessor">.postFinish</span>(request)<span class="hljs-comment">;</span> continue<span class="hljs-comment">;</span> } // Perform the network request. NetworkResponse networkResponse = mNetwork<span class="hljs-preprocessor">.performRequest</span>(request)<span class="hljs-comment">;</span> request<span class="hljs-preprocessor">.addMarker</span>(<span class="hljs-string">"network-http-complete"</span>)<span class="hljs-comment">;</span> // Parse the response here on the worker thread. Response<?> response = request<span class="hljs-preprocessor">.parseNetworkResponse</span>(networkResponse)<span class="hljs-comment">;</span> request<span class="hljs-preprocessor">.addMarker</span>(<span class="hljs-string">"network-parse-complete"</span>)<span class="hljs-comment">;</span> // Write to cache if applicable. if (mCache != null && request<span class="hljs-preprocessor">.shouldCache</span>() && response<span class="hljs-preprocessor">.cacheEntry</span> != null) { response<span class="hljs-preprocessor">.cacheEntry</span><span class="hljs-preprocessor">.expireTime</span> = request<span class="hljs-preprocessor">.getCacheExpireTime</span>()<span class="hljs-comment">;</span> mCache<span class="hljs-preprocessor">.putEntry</span>(request<span class="hljs-preprocessor">.getCacheKey</span>(), response<span class="hljs-preprocessor">.cacheEntry</span>)<span class="hljs-comment">;</span> request<span class="hljs-preprocessor">.addMarker</span>(<span class="hljs-string">"network-cache-written"</span>)<span class="hljs-comment">;</span> } // Post the response back. request<span class="hljs-preprocessor">.markDelivered</span>()<span class="hljs-comment">;</span> mDelivery<span class="hljs-preprocessor">.postResponse</span>(request, response)<span class="hljs-comment">;</span></code><ul class="pre-numbering"><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li><li>10</li><li>11</li><li>12</li><li>13</li><li>14</li><li>15</li><li>16</li><li>17</li><li>18</li><li>19</li><li>20</li><li>21</li><li>22</li><li>23</li><li>24</li><li>25</li><li>26</li><li>27</li><li>28</li><li>29</li><li>30</li><li>31</li></ul><ul class="pre-numbering"><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li><li>10</li><li>11</li><li>12</li><li>13</li><li>14</li><li>15</li><li>16</li><li>17</li><li>18</li><li>19</li><li>20</li><li>21</li><li>22</li><li>23</li><li>24</li><li>25</li><li>26</li><li>27</li><li>28</li><li>29</li><li>30</li><li>31</li></ul>
從上述程式碼看出,回撥確實很多,若在這些回撥中新增太多操作的話,肯定會影響資料請求的速度。
總的來說,netroid相對volley的改進還是不錯的,這也是這兩天看程式碼的總結,如有遺漏,後面再補充!