zoukankan      html  css  js  c++  java
  • Volley的基本使用

    本人初学,如有纰缪,望指正~
     
      Volley是Google在2003年的I/O大会上推出的通信框架,结合了AsyncHttpClient和Universal-Image-Loader的优点——简化了http的使用 + 异步加载图片的神奇能力。Android中的Http实现主要有HttpUrlConnection和HttpClient两种,关于二者的选择Google在Blog中表示推荐在姜饼小人(API level = 9)及以上的版本中使用Java的HttpUrlConnection而在之前的版本使用Apache的HttpClient,这在Volley这个框架中也有明确的体现。
     
    获取Volley
    git clone https://android.googlesource.com/platform/frameworks/volley
    把它编译成jar文件就可以加入libs了
     
    一、简单的请求(以StringRequest为例)
      Http的通信最主要的部分应该就是发出请求和接收响应了,所以Volley的比较核心的一个类就是RequestQueue,一个请求队列。它负责管理工作线程,读写缓存,和解析、分发响应(具体操作还是由具体的类实现),即将发出的Http请求都会首先聚集在这里等待工作线程来实现请求。RequestQueue可以被看成一艘载满Http请求的航空母舰,而工作线程就是弹射器喽。
      所以按照航母起飞飞机的步骤,我们可以猜到利用Volley进行Http通信的简单步骤:
        1.获取RequestQueue(得到一艘航母,可以是自己造的,也可以是委托别人造的,下面会提到)
        2.实例化一个Request(得到一架飞机,你也知道飞机又很多类型啦)
        3.将Request加入RequestQueue,等待工作线程将其发送出去(把飞机从机库升上起飞甲板,等待弹射器把它扔出去)
     
    起飞侦察机-发出GET请求
      按照上面的步骤,第一步就是建立一个请求队列,最简单的方法就是用Volley.newRequestQueue(),这是一个特别方便的静态方法,替我们默认实现了所有需要的东西(网络、缓存等,这些在Volley中都有默认实现),它会返回一个已经开始运行的RequestQueue(相当于别人帮忙造了艘航母)。之后我们需要的只是设置好请求的响应监听接口,把请求加入到这个队列中就可以等着响应数据来敲门了。下面是Google文档中的示例代码:
     1   //初始化一个请求队列
     2   RequestQueue queue = Volley.newRequestQueue(this);
     3   String url ="http://www.google.com";
     4   
     5   //根据给定的URL新建一个请求
     6   StringRequest stringRequest = new StringRequest(Request.Method.GET, url,
     7               new Response.Listener() {
     8       @Override
     9       public void onResponse(String response) {
    10          //在这里操作UI组件是安全的,因为响应返回时这个函数会被post到UI线程来执行
    11          // 在这里尽情蹂躏响应的String。
    12      }
    13  }, new Response.ErrorListener() {
    14      @Override
    15      public void onErrorResponse(VolleyError error) {
    16          // 出错了怎么办?凉拌!并且在这里拌。
    17      }
    18 });
    19 // 把这个请求加入请求队列
    20 queue.add(stringRequest);
    StringRequest是Request的具体实现之一,代表解析后的响应数据是一个字符串,相似的还有JsonRequest(包括JsonObjectRequest和JsonArrayRequest两个可以使用的子类)、ImageRequest来满足基本的使用,用法大同小异。主要是构造参数不一样,分别如下:
      1.public StringRequest(int method, String url, Listener<String> listener,ErrorListener errorListener);
         参数说明:从左到右分别是请求方法(都封装在Request中的Method接口内),请求URL,响应监听接口实例,错误监听接口实例。
      2.public JsonObjectRequest(int method, String url, JSONObject jsonRequest,Listener<JSONObject> listener, ErrorListener errorListener);
         public JsonObjectRequest(String url, JSONObject jsonRequest, Listener<JSONObject> listener,ErrorListener errorListener);
         参数说明:如果是GET请求的话,jsonRequest传入null就可以了,否则在未指明请求方法的情况下(也就是第二个构造函数)会默认为POST请求。其他同上。
      3.public JsonArrayRequest(String url, Listener<JSONArray> listener, ErrorListener errorListener);
         参数说明:同上。
      4.public ImageRequest(String url, Response.Listener<Bitmap> listener, int maxWidth, int maxHeight,Config decodeConfig, Response.ErrorListener errorListener);
         参数说明:decodeConfig是图片的颜色属性,下面的几个值都可以使用。
     
    Bitmap.Config中的颜色属性(枚举类型)
    ALPHA_8  
    ARGB_4444 由于质量低,已经被弃用,推荐用ARGB_8888
    ARGB_8888 每个像素用4byte存储
    RGB_565 每个像素用2byte存储,红色占5位,绿色占6位,蓝色占5位
     
    起飞战斗机-发出POST请求
      基本方式和上面一样,但是怎么装导弹,啊不,是怎么提交的数据呢?
    Volley会在Request的请求方法是POST(还有PUT和PATCH)的情况下调用Request类(就是XXXRequest的父类)的getParam()函数来获取参数,提前剧透,如果使用的是HttpUrlConnection的话,调用getParam()是在HurlStatck中的addBodyIfExists()函数实现的,感兴趣的话可以去看一下哈。所以,POST请求像下面这样就可以了。
     1 //初始化一个请求队列
     2 RequestQueue queue = Volley.newRequestQueue(this);
     3 String url ="http://www.google.com";
     4 
     5 //根据给定的URL新建一个请求
     6 StringRequest stringRequest = new StringRequest(Request.Method.POST, url,
     7    new Response.Listener() {
     8     @Override
     9     public void onResponse(String response) {
    10         // 在这里处理请求得到的String类型的响应
    11    }
    12 }, new Response.ErrorListener() {
    13     @Override
    14     public void onErrorResponse(VolleyError error) {
    15         // 在这里进行出错之后的处理
    16    }
    17 }) {
    18 @Override
    19 protected Map<String, String> getParams() throws AuthFailureError {
    20 
    21 Map<String, String> map = new HashMap<String, String>(); 
    22         map.put("params1", "value1"); 
    23         map.put("params2", "value2"); 
    24         return map
    25  };
    26 // 把这个请求加入请求队列
    27 queue.add(stringRequest);
     
    后悔药-取消请求
      Request中有一个cancel()方法,调用这个就可以取消当前请求了,但是取消到哪一个层次就不一定了,但是Volley可以保证响应处理函数(就是onResponse()和onErroeResponse())不会被调用。还有一个一起取消多个请求,就是在发出请求前调用Request的setTag()方法为每个请求加一个标签,这个方法的参数是Object,所以我们可以使用任何类型作为标签。这样就可以调用ReqiestQueue的cancelAll()函数取消一群标签了。比较常用的方法就是,将发出这个请求的Activity或者Fragment作为标签,并在onStop()中调用cancelAll()。
     
    二、使用ImageLoader加载图片
      ImageLoader是一个可以实现图片异步加载的类,但已经不是继承与Request了。ImageLoader虽然是头神兽,但必须在主线程召唤它,否则会抛出错误IllegalStateException,可能是因为ImageLoader在图片返回时要直接操作ImageView,在主线程里操作UI组件才是安全的,so~
      用ImageLoader加载图片分三步
        1.创建ImageLoader
        2.获取一个ImageListener对象
        3.调用ImageLoader的get()方法获取图片
      ImageLoader的构造函数长成这样:public ImageLoader(RequestQueue queue, ImageCache imageCache);
    所以实例化一个ImageLoader需要一个RequestQueue(之前建立的就行),还有一个ImageCache,这是一个ImageLoader内部定义的接口,用来实现L1缓存——内存缓存(Volley在RequestQueue中已经实现了L2缓存——文件缓存)。ImageLoader中并没有对传入的ImageCache在使用前判空的代码,传null进去会出错的。如果实在不想弄内存缓存,实现一个什么都不做的ImageCache就好了。下面是代码:
     1 ImageLoader imageLoader = new ImageLoader(mRequestQueue, new ImageCache() {  
     2     @Override  
     3     public void putBitmap(String url, Bitmap bitmap) {  
     4     }  
     5   
     6     @Override  
     7     public Bitmap getBitmap(String url) {  
     8         return null;  
     9     }  
    10 });
    11 
    12 //default_image是正在加载图片时占位用的
    13 //error_image是加载不成功时显示的图片
    14 ImageListener listener = ImageLoader.getImageListener(imageView, R.drawable.default_image, R.drawable.error_image); 
    15imageLoader.get("your image url", listener); 
      除了ImageLoader之外Volley中还有一个Image加载的神器——NetworkImageView,使用步骤如下:
        1.在布局文件中加入控件,并在Java代码中获取实例
        2.设置default_image,error_image,图片URL,一个ImageLoader对象
      代码如下:
    1 networkImageView = (NetworkImageView) findViewById(R.id.network_image_view); 
    2 networkImageView.setDefaultImageResId(R.drawable.default_image);  
    3 networkImageView.setErrorImageResId(R.drawable.error_image);
    4 networkImageView.setImageUrl("your image url", imageLoader);  
    三、Google推荐的用法
      上面就是Volley的基本用法了,但是如果一个App需要频繁的网络通信的话,建立多个RequestQueue是件很奇怪的事儿(谁会因为临时有飞机要在海上起飞就去新建一艘航母呢,这得多有钱啊),所以Google推荐我们只实例化一个RequestQueue来应付频繁的Http通信,当然,要保证队列的寿命和App一样长。如何实现呢?Google又说了,不推荐在App的Application.onCretae()方法中实例化一个RequestQueue(不过确实是个简单的方法哈),最好是建立一个单例模式的类,并把所有我们需要用到的Volley的瓶瓶罐罐都放进去,这样显得更模块化。下面就是示例代码。这段代码中最重要的就是RequestQueue要用Application的Context实例化,要不然就会随着Activity的生命周期不停重建。其实,像AsyncHttpClient中的纯静态使用方法也不错(详情见:http://loopj.com/android-async-http/)
    PS:下面还实现了一个简单的ImageCache
     1 private static MySingleton mInstance;
     2     private RequestQueue mRequestQueue;
     3     private ImageLoader mImageLoader;
     4     private static Context mCtx;
     5 
     6     private MySingleton(Context context) {
     7         mCtx = context;
     8         mRequestQueue = getRequestQueue();
     9 
    10         mImageLoader = new ImageLoader(mRequestQueue,
    11                 new ImageLoader.ImageCache() {
    12             private final LruCache<String, Bitmap>
    13                     cache = new LruCache<String, Bitmap>(20);
    14 
    15             @Override
    16             public Bitmap getBitmap(String url) {
    17                 return cache.get(url);
    18             }
    19 
    20             @Override
    21             public void putBitmap(String url, Bitmap bitmap) {
    22                 cache.put(url, bitmap);
    23             }
    24         });
    25     }
    26 
    27     public static synchronized MySingleton getInstance(Context context) {
    28         if (mInstance == null) {
    29             mInstance = new MySingleton(context);
    30         }
    31         return mInstance;
    32     }
    33 
    34     public RequestQueue getRequestQueue() {
    35         if (mRequestQueue == null) {
    36             // getApplicationContext()是关键, 它会避免
    37             // Activity或者BroadcastReceiver带来的缺点.
    38             mRequestQueue = Volley.newRequestQueue(mCtx.getApplicationContext());
    39         }
    40         return mRequestQueue;
    41     }
    42 
    43     public <T> void addToRequestQueue(Request<T> req) {
    44         getRequestQueue().add(req);
    45     }
    46 
    47     public ImageLoader getImageLoader() {
    48         return mImageLoader;
    49     }
    50 }
    四、Volley是怎么管理请求的呢?
      RequestQueue会维护一个缓存调度线程(cache线程)和一个网络调度线程池(net线程)(注意,这是一池子线程),当一个Request被加到队列中的时候,cache线程会把这个请求进行筛选:如果这个请求的内容可以在缓存中找到,cache线程会亲自解析相应内容,并分发到主线程(UI)。如果缓存中没有,这个request就会被加入到另一个NetworkQueue,所有真正准备进行网络通信的request都在这里,第一个可用的net线程会从NetworkQueue中拿出一个request扔向服务器。当响应数据到的时候,这个net线程会解析原始响应数据,写入缓存,并把解析后的结果返回给主线程。如下图:
     
    所以,读源码的话也可以把源码分成四层,如下图:(其余的类都可以归到“方便的工具类”中,比如ImageLoader,ClearCacheRequest等等)。
     
     
  • 相关阅读:
    C++笔记(2018/2/6)
    2017级面向对象程序设计寒假作业1
    谁是你的潜在朋友
    A1095 Cars on Campus (30)(30 分)
    A1083 List Grades (25)(25 分)
    A1075 PAT Judge (25)(25 分)
    A1012 The Best Rank (25)(25 分)
    1009 说反话 (20)(20 分)
    A1055 The World's Richest(25 分)
    A1025 PAT Ranking (25)(25 分)
  • 原文地址:https://www.cnblogs.com/liu37130/p/3902390.html
Copyright © 2011-2022 走看看