zoukankan      html  css  js  c++  java
  • 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个,可以根据自己需求添加或减少。






  • 相关阅读:
    Spring注释事务失效及解决办法
    在使用springMVC时,我使用了@Service这样的注解,发现使用注解@Transactional声明的事务不起作用
    如何在Oracle中复制表结构和表数据
    Tomcat Deployment failure ,locked one or more files
    java中对List中对象排序实现
    HDU 5002 Tree LCT 区间更新
    2014-2015 ACM-ICPC, Asia Xian Regional Contest G The Problem to Slow Down You 回文树
    Codeforces Round #323 (Div. 1) B. Once Again... 暴力
    Codeforces Round #323 (Div. 2) C. GCD Table 暴力
    hdu 5497 Inversion 树状数组 逆序对,单点修改
  • 原文地址:https://www.cnblogs.com/epmouse/p/7542084.html
Copyright © 2011-2022 走看看