zoukankan      html  css  js  c++  java
  • volle介绍02

    ----------------------------------------------------------------------------

    转载:http://blog.csdn.net/crazy__chen/article/details/46483329

    ----------------------------------------------------------------------------

    Volley是一款由Google 推出的 Android 异步网络请求框架和图片加载框架,特别适合数据量小,通信频繁的网络操作。

    大家可以在这个地址https://android.googlesource.com/platform/frameworks/volley/下载源码

    Volley 的主要特点

    (1). 扩展性强。Volley 中大多是基于接口的设计,可配置性强。
    (2). 一定程度符合 Http 规范,包括返回 ResponseCode(2xx、3xx、4xx、5xx)的处理,请求头的处理,缓存机制的支持等。并支持重试及优先级定义。
    (3). 默认 Android2.3 及以上基于 HttpURLConnection,2.3 以下基于 HttpClient 实现
    (4). 提供简便的图片加载工具。

    本专栏主要通过解析volley的源码,对它的整个架构进行分析,指出它这样设计架构,对应扩展性,耦合等优势。同时,指出volley对于网络请求,考虑到的细节方面,用于指导我们日后自己写网络框架的需求。另外还会根据volley的设计,说明它所应用的场景,volley所面临的不足,以及它本身可以怎么被更完善的扩展。

    本篇文章作为专栏的开篇,会先给简单大家介绍volley的使用和volley的整个架构设计,通过对架构的介绍,希望大家对volley的实现模式有个大体的印象。在这篇文章中,大家不必要关注实现的细节(因为在接下来的文章会详细介绍),主要做到的是体会volley的设计思路,关注整体的实现。

    网上介绍volley如何使用的文章有很多,大家可以自行搜索一下,这里我举一个简单的例子说明如何使用volley进行网络请求。

    StringRequest stringRequest = new StringRequest("http://www.baidu.com",  
        new Response.Listener<String>() {  
            @Override  
            public void onResponse(String response) {  
                //处理响应  
            }  
        }, new Response.ErrorListener() {  
            @Override  
                public void onErrorResponse(VolleyError error) {  
                   //处理错误  
            }  
        });  
    

      

    有上面的代码我们可以看出,我们实例化了一个StringRequest对象,其中有一个网络地址www.baidu.com,两个监听器

    观察监听器里面的方法,一个参数是String response,一个是VolleyError error

    从字面上的意思理解,我们创建了一个网络请求对象request,传入请求的地址,请求成功以后,会回调两个监听器的方法,两个监听器分别对应请求成功与请求失败的情况。

    OK,是不是只要这样就已经开启了线程去请求数据了呢。没有这么简单,我们还要:

    RequestQueue mQueue = Volley.newRequestQueue(context); //创建请求队列  
    mQueue.add(stringRequest); //将请求添加到请求队列  
    

      

    上面的操作,将我们构造的请求,添加到一个新建的请求队列里面。到此为止,我们就成功地发出了请求,并且在请求结束以后,会回调我们request里面的方法。

    这就是volley最简单的使用。

    有人会问,为什么要将请求加入队列里面,我直接new一个Request,然后在Request内部建立线程,请求数据,最后回调接口不就好了吗?

    这样想是没有错,但是volley这样设计必然有自己的原因,就耦合过紧这一点而言,就可以知道我们上面提出的策略并不是那么的优雅(不代表不可行)。

    那么volley是怎么做到呢?我们先来看一张volley的整体架构图(该图出自http://codekk.com/open-source-project-analysis/detail/Android/grumoon/Volley%20%E6%BA%90%E7%A0%81%E8%A7%A3%E6%9E%90,如果不允许转载,请联系我)

    上面的图有点复杂,大家先不要纠结,我们先来看我们之前的结论,volley的使用过程是

    1,创建request

    2,将request放入队列RequestQueue

    3,处理回调结果

    注意到例子中使用的StringRequest,对应上面的图,找到Request和StringRequest可以知道,StringRequest是Request的一个子类,从字面上可以知道,这是一个字符串请求,另外还有json,image请求等,都是request的子类,所以我们设想,是不是不同的请求,有一个不同的类呢?

    正是这样的,从面向对象的角度,我们把请求看成是一个类,所以我们每次的网络请求,只有new出一个类,然后加入队列就可以了。

    那么队列里面是怎么样替我请求数据的呢?这里我给大家介绍其中的奥秘,大家只要了解过程就可以,不必深究细节。

    其实RequestQueue里面有两个队列,一个我称为缓存队列mCacheQueue,一个称为网络队列mNetworkQueue

    如果请求要求加入缓存队列(例如我们给request设置一个属性ShouldCache,然后提供set方法来设置),将会试图从硬盘缓存中获取数据,如果没有缓存,这个请求将被放入网络队列

    如果请求不要求缓存,则直接加入网络队列。

    加入队列以后,我们开启线程,从队列中取出请求。

    可想而知,我们最好有一个线程CacheDispatcher从缓存队列中取,一个NetworkDispatcher从网络队列中取,然而网络请求往往大量,所以volley实际上有多个线程同时从网络队列中取出请求(这里涉及线程同步,volley使用PriorityBlockingQueue解决)

    为什么要先建立几个线程,从队列中取,而不是每个request开启一个线程呢?这样做的好处是避免重复大量创建线程所带来的开销,另外由于所有的request都存在在一个RequestQueue里面,便于我们对request的管理,例如我们要关闭某个request,又或者我们请求了很多相同的request,对应这些操作,我们如果将request分散,是很难统一解决的,所以这样用类似线程池的思想,统一管理线程。

    同时,这样做又会带来不利,因为实际请求线程的线程数目是固定的,意味着当request数目大于线程数目时,有的线程将被阻塞,造成效率下降,更多的问题,会在接下来的文章提到。

    至于CacheDispatcher和NetworkDispatcher是怎么请求数据的呢?

    对于NetworkDispatcher而言,必然是开启网络连接,然后获取数据的(例如url.openConnection),这是我们的常用实现,先不做详细解释(volley对这些实现进行了更详细的封装)

    再来考虑,获得结果以后,我们怎么回调。

    还是面向对象的思路,volley将响应结果封装成一个repsonse类(和request对应)

    对应NetworkDispatcher而言,在它的run()方法里面,取得request以后,根据url请求数据,将数据封装成respsonse对象,再有一个分发器ResponseDelivery分发到对应的request

    有人会问?解析到response以后,我们给request设计一个方法(例如将parseRespose(Respsonse respsonse))用于使用response,同时在这个方法内,回调监听器不就好了吗?为什么要多此一举,创建一个分发器呢?

    原因是这样更灵活,但是还有一个重要的原因是,注意到我们回调,往往是在主线程中进行的(因为很可能要操作UI),如果我们在NetworkDispatcher(子线程)里面,直接回调,可能造成错误,这是ResponseDelivery存在的另外一个原因。

    根据上面的结论,最后来看一张简单的流程图

    根据流程分析,我们可以体会到,volley设计框架的基本思路,对比于我们简单的实现,volley的实现方式耦合更加松散,使用面向接口编程,同时使用更多组合方式而不是继承。使用了代理等设计模式,同时提高了线程的利用率。总之volley的架构设计又各种各样的好处。

    我在这里介绍几个volley的功能,以及它考虑到的,而我们很可能没有考虑到的问题。这些问题或者说功能上的优势,会伴随着本专栏的深入让大家逐渐体会。

    下面只是笼统的介绍,大家可以对比自己的想法,看看自己是不是有什么考虑不周的(如果是你实现这样一个框架的话)

    1,Request的设计,我们在得到response之后,我们可能根据项目需求希望有不同形式的数据(例如string,bitmap,jsonObject),volley使用抽象编程,让我们可以继承Request实现自己对response的解析方式(意味着处理volley为我们提供的StringRequest类等,我们自定义request)

    2,重试策略,网络请求可能因为网络原因失败(例如手机断网了),volley为我们提供了重试策略

    3,终止请求,例如请求数据途中,我们希望终止该请求

    4,request在队列中优先级的问题,例如我们有的请求比较紧迫,就应该排在队列的前面

    5,重复请求的问题,利用有多个相同的request在队列之中,请求到其中一个,其他的可能就不必请求了,直接从缓存中取

    6,异常的处理,例如io,403,402等授权错

    7,地址重定向处理

    8,网络问题的处理,例如我们断网了,volley使用了network这个类来处理这一类问题

    9,使用HttpClient还是url.openConnection()去请求数据呢?

    10,缓存的读取和存储,我们请求到网络数据以后,可以存入本地缓存

    11,如何设置请求日志来记录请求信息,用于调试?

    12,对于缓存写入和读取的效率优化

    13,图片请求的处理

    现在就让我们来小试牛刀,先来看Volley这个类,Volley作为整个框架的入口,其实就是创建了一个RequestQueue队列

    public class Volley {  
      
        /**  
         * Default on-disk cache directory. 
         * 默认缓存目录名  
         */  
        private static final String DEFAULT_CACHE_DIR = "volley";  
      
        /** 
         * Creates a default instance of the worker pool and calls {@link RequestQueue#start()} on it. 
         * You may set a maximum size of the disk cache in bytes. 
         * 创建一个默认工作池,并且启动请求队列 
         * @param context A {@link Context} to use for creating the cache dir.用于创建缓存目录 
         * @param stack An {@link HttpStack} to use for the network, or null for default. 
         * @param maxDiskCacheBytes the maximum size of the disk cache, in bytes. Use -1 for default size. 
         * 硬盘缓存最大值,-1则默认 
         * @return A started {@link RequestQueue} instance. 
         */  
        public static RequestQueue newRequestQueue(Context context, HttpStack stack, int maxDiskCacheBytes) {  
            File cacheDir = new File(context.getCacheDir(), DEFAULT_CACHE_DIR);//缓存队列  
      
            String userAgent = "volley/0";  
            try {  
                String packageName = context.getPackageName();//包名  
                PackageInfo info = context.getPackageManager().getPackageInfo(packageName, 0);  
                userAgent = packageName + "/" + info.versionCode;  
            } catch (NameNotFoundException e) {  
            }  
      
            if (stack == null) {//如果没有限定stack  
                if (Build.VERSION.SDK_INT >= 9) {//adk版本在9或者以上  
                    stack = new HurlStack();  
                } else {  
                    // Prior to Gingerbread, HttpUrlConnection was unreliable.  
                    // See: http://android-developers.blogspot.com/2011/09/androids-http-clients.html  
                    stack = new HttpClientStack(AndroidHttpClient.newInstance(userAgent));  
                }  
            }  
      
            Network network = new BasicNetwork(stack);  
              
            RequestQueue queue;  
            if (maxDiskCacheBytes <= -1)//小于等于-1,则默认值  
            {  
                // No maximum size specified  
                queue = new RequestQueue(new DiskBasedCache(cacheDir), network);  
            }  
            else  
            {  
                // Disk cache size specified  
                queue = new RequestQueue(new DiskBasedCache(cacheDir, maxDiskCacheBytes), network);  
            }  
      
            queue.start();  
      
            return queue;  
        }  
    

      

    可以看到,Volley的newRequestQueue()方法里面,根据版本创建了stack(分别是HurlStack和HttpClientStack)。至于不同adk版本会创建不同的stack,是由于android的版本原因,在9以上版本使用HurlStack比HttpClientStack更加好。

    然后创建了网络类BasicNetwork,缓存类DiskBasedCache,然后使用这两个来创建RequestQueue对象。

    或许现在大家还不明白这两个类的作用,大家只需要记得创建RequestQueue需要这两个类就可以了。

    OK,作为本专栏的开篇文章,主要是为大家提供阅读的兴趣和思路。在接下来的文章里面,我就会结合具体的源代码,来说明volley的具体实现。

  • 相关阅读:
    Open source cryptocurrency exchange
    Salted Password Hashing
    95. Unique Binary Search Trees II
    714. Best Time to Buy and Sell Stock with Transaction Fee
    680. Valid Palindrome II
    Java compiler level does not match the version of the installed Java project facet.
    eclipse自动编译
    Exception in thread "main" java.lang.StackOverflowError(栈溢出)
    博客背景美化——动态雪花飘落
    java九九乘法表
  • 原文地址:https://www.cnblogs.com/aprz512/p/5316673.html
Copyright © 2011-2022 走看看