Volley 源码解读

  大家都知道谷歌现在已经不维护volley框架,为什么现在还要分析volley源码呢。

     首先,volley框架的设计思想是非常值得借鉴,翻下当下个人开源 的一些网络框架,很多都是借鉴的volley的设计思想完成的。

     另外,volley 源码相对简单易懂。

 

一、首先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来完成网络数据的获取和解析。

具体使用代码就不写了。

二、源码分析

 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     }

 

1、创建一个请求队列会调用Volley类中的 newRequestQueue方法。我们主要看第24、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     }

2、创建一个缓存线程4、5行和四个网络请求线程8--12行。(mDispatchers.length默认值为4)并 调用他们的start()方法

    CacheDispatcher和NetworkDispatcher都是继承于 Thead类的。start的方法就是启动该线程

3、大家都熟悉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会浪费大量资源。

本篇总结:

1、new出一个队列  requestQueue

2、new出一个合适的request

3、把request加入(add)到队列中去执行

4、requestQueue 只建议new一次,也就是在app中,只维护一个requestqueue,之后的网络请求都是往此队列中添加request即可。

5、requestQueue  默认是5个线程,缓存一个,网络请求4个,可以根据自己需求添加或减少。

 






 

posted @ 2017-09-18 11:09  epmouse  阅读(329)  评论(0编辑  收藏  举报