Volley—轻量级HTTP客户端网络请求框架

介绍

Volley的中文翻译为“齐射、并发”,是在2013年的Google大会上发布的一款Android平台网络通信库,具有网络请求的处理、小图片的异步加载和缓存等功能,能够帮助 Android APP 更方便地执行网络操作,而且更快速高效。

为什么是Volley?(了解)

避开HttpUrlConnection 和HttpClient

在较低的api版本中(多数是在Gingerbread和Froyo中),HttpUrlConnection和HttpClient 远未达到完美。有一些已知的问题 和bugs 一直未被修复,HttpClient 自上次api更新(API 22)之后就已经过时,意味着不再维护,后续可能也会被移除。
这就是需要转到一个更稳定的处理网络请求的方法的主要原因。

也为了避开AsyncTask
这里写图片描述

它速度更快

前些时候,Google+团队针对每种可以使用的网络请求方式做了一些列的性能测试。当应用在RESTful 风格的应用中时,Volley的得分比其他候选方法高近10倍。

它可以缓存所有东西
Volley可以自动缓存请求,这点确实是关乎生死的问题。让我们暂时回到上面所提到的那个例子。你有一个item的列表 - 假设是JSON 数组 - 并且每个item都包括一段描述和一个缩略图。现在设想一下用户旋转屏幕之后会发生的事情:activity销毁,列表重新加载,同样的还有图片。长话短说就是:严重的资源浪费以及糟糕的用户体验。

事实证明,Volley在克服这种困难中是相当有用的。它可以记住前一个调用同时处理Activity的销毁与重建。它缓存所有的东西,这点你也不用担心。

Small Metadata Operations
Volley在轻量级的调用中堪称完美,比如请求JSON对象,或者列表的一部分,或者被选中item的详情等等。它是为RESTful应用设计的,在这种特定场景下可以发挥自己最好的优势。

但是当把它应用在数据流或者大文件下载中,就不是那么好了。这就是为什么它叫Volley(万箭齐发),而不是叫加农炮。

Volley 优点具体总结:

自动调度网络请求;
高并发网络连接;
通过标准的 HTTP cache coherence(高速缓存一致性)缓存磁盘和内存透明的响应;
支持指定请求的优先级;
网络请求cancel机制。我们可以取消单个请求,或者指定取消请求队列中的一个区域;
框架容易被定制,例如,定制重试或者回退功能;
包含了调试与追踪工具;
Volley 不适合用来下载大的数据文件。因为 Volley 会保持在解析的过程中所有的响应。

这里写图片描述

主线程

在主线程中,你只允许触发请求与处理返回结果,不能多也不能少。

其结果就是你实际上可以忽略在使用AsyncTask的时候doInBackground 方法里面所做的事情。Volley 自动管理http传输同时捕获网络错误,这些都是以前需要我们自己考虑的。

缓存与网络线程

当你向队列中添加了一个请求,背后发生了几件事情。Volley会检查这个请求是否可以从缓存中得到。如果可以,缓存将负责读取,解析,和分发。否则将传递给网络线程。

在网络线程中,一些列的轮询线程不断的在工作。第一个可用的网络线程线程让请求队列出列,发出http请求,解析返回的结果,并写入到缓存中。最后,把解析的结果分发给主线程的listener中。

Volley中的RequestQueue 和 Request

RequestQueue 用来执行请求的请求队列
Request 用来构造一个请求对象

Request对象主要有以下几种类型:

  • StringRequest 响应的主体为字符串
  • JsonArrayRequest 发送和接收JSON数组
  • JsonObjectRequest 发送和接收JSON对象
  • ImageRequest 发送和接收Image

Volley的基本使用
首先我们需要创建一个RequestQueue requestQueue,然后构建一个自己所需要的XXRequest req,之后通过requestQueue.add(req);将请求添加至请求队列;

StringRequest的用法:

Get请求

搭建volley的开发环境

 compile 'com.android.volley:volley:1.0.0'

权限

 <uses-permission android:name="android.permission.INTERNET"/>

通常Volley只会用到两个类RequestQueue 和Request,你首先创建一个RequestQueue,RequestQueue管理工作线程并将解析的结果发送给主线程。然后你传递一个或者多个Request
对象给他。

Request 的构造函数的参数总是包含类型(GET, POST, 等等),数据源的url,以及事件监听者。根据请求类型的不同,可能还需要一些其他的参数。

public class MainActivity extends AppCompatActivity {

    private TextView textView;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        textView = (TextView) findViewById(R.id.text);
    }

使用Volley发送请求

 public void request(View view) throws UnsupportedEncodingException {
        //创建返回类型为String的请求
        //请求方式
        int method= Request.Method.GET;
        //请求连接
        // String url="https://www.baidu.com";
        String value= URLEncoder.encode("中国","UTF-8");
        String url="http://192.168.79.28:8080/webapi/get?name="+value;
        //创建了成功返回数据回调对象
        Response.Listener<String> listener=new Response.Listener<String>() {
            //请求成功后,返回数据的方法编写业务逻辑
            @Override
            public void onResponse(String response) {
                textView.setText(response);
            }
        };
        //创建请求失败的回调对象
        Response.ErrorListener errorListener=new Response.ErrorListener() {
            //请求失败后,返回异常的方法编写业逻辑
            @Override
            public void onErrorResponse(VolleyError error) {
                error.printStackTrace();
                textView.setText("错误信息"+error.getMessage());
            }
        };

     StringRequest request=new StringRequest(method,url,listener,errorListener);
        //由于请求创建了之后,需要添加一个队列集合中进行发送,所以我们创建ReqeustQueue;
        RequestQueue requestQueue= Volley.newRequestQueue(this);
        requestQueue.add(request);
    }
StringRequest:返回类型为String  json/xml
- RequestQueue:请求队列,发送请求
- Response.Listener<String>:成功的响应处理
- Response.ErrorListener:失败的响应处理

Post请求
从get请求切换到post请求是非常简单的。你只需要在request的构造方法中改变Request.Method,同时重写getParams方法,返回包含请求参数的Map

//请求方式登录
  int method=Request.Method.POST;
  //post?username=itheima&password=123
  String url="http://192.168.79.28:8080/webapi/post";
 StringRequest request=new StringRequest(method,url,listener,errorListener){
            //默认返回null,如果你想使用post方式提交参数,必须覆盖重写这个getParams来提交参数
            @Override
            protected Map<String, String> getParams() throws AuthFailureError {
                Map<String, String> map=new HashMap<>();
                map.put("username","itheima");
                map.put("password","123");
                return map;
            }
        };

取消一个请求
如果你想取消所有的请求,在onStop方法中添加如下代码:

@Override
protected void onStop() {
    super.onStop();
    mRequestQueue.cancelAll(new RequestQueue.RequestFilter() {
        @Override
        public boolean apply(Request<?> request) {
            // do I have to cancel this?
            return true; // -> always yes
        }
    });
}

这样你就不必担心在onResponse被调用的时候用户已经销毁Activity。这种情况下会抛出NullPointerException异。但是post请求则需要继续,即使用户已经改变了Activity。我们可以通过使用tag来做到,在构造GET请求的时候,添加一个tag给它。

request.setTag("GET");
mRequestQueue.add(request);

如果要取消GET请求,只需简单的添加下面的一行代码:

mRequestQueue.cancelAll("GET");

这样你就只会取消GET请求,让其它请求不受影响。注意你必须手动在销毁的Activity中处理这种情况。

JsonRequest的用法

类似于StringRequest,JsonRequest也是继承自Request类的,不过由于JsonRequest是一个抽象类,因此我们无法直接创建它的实例,那么只能从它的子类入手了。JsonRequest有两个直接的子类,JsonObjectRequest和JsonArrayRequest,从名字上你应该能就看出它们的区别了吧?一个是用于请求一段JSON数据的,一个是用于请求一段JSON数组的。

至于它们的用法也基本上没有什么特殊之处,先new出一个JsonObjectRequest对象,如下所示:

JsonObjectRequest jsonObjectRequest = new JsonObjectRequest("http://m.weather.com.cn/data/101010100.html", null,  
        new Response.Listener<JSONObject>() {  
            @Override  
            public void onResponse(JSONObject response) {  
                Log.d("TAG", response.toString());  
            }  
        }, new Response.ErrorListener() {  
            @Override  
            public void onErrorResponse(VolleyError error) {  
                Log.e("TAG", error.getMessage(), error);  
            }  
        });  

可以看到,这里我们填写的URL地址是http://m.weather.com.cn/data/101010100.html,这是中国天气网提供的一个查询天气信息的接口,响应的数据就是以JSON格式返回的,然后我们在onResponse()方法中将返回的数据打印出来。

最后再将这个JsonObjectRequest对象添加到RequestQueue里就可以了,如下所示:

mQueue.add(jsonObjectRequest); 

这样当HTTP通信完成之后,服务器响应的天气信息就会回调到onResponse()方法中,并打印出来。现在运行一下程序,发出这样一条HTTP请求,就会看到LogCat中会打印出如下图所示的数据。
这里写图片描述

由此可以看出,服务器返回给我们的数据确实是JSON格式的,并且onResponse()方法中携带的参数也正是一个JSONObject对象,之后只需要从JSONObject对象取出我们想要得到的那部分数据就可以了。

你应该发现了吧,JsonObjectRequest的用法和StringRequest的用法基本上是完全一样的,Volley的易用之处也在这里体现出来了,会了一种就可以让你举一反三。

ImageRequest的用法

StringRequest和JsonRequest的用法,并且总结出了它们的用法都是非常类似的,基本就是进行以下三步操作即可:

  1. 创建一个RequestQueue对象。
  2. 创建一个Request对象。
  3. 将Request对象添加到RequestQueue里面。

其中,StringRequest和JsonRequest都是继承自Request的,ImageRequest也是继承自Request的,因此它的用法也是基本相同的,首先需要获取到一个RequestQueue对象,可以调用如下方法获取到:

RequestQueue mQueue = Volley.newRequestQueue(context);  

接下来自然要去new出一个ImageRequest对象了,代码如下所示:

ImageRequest imageRequest = new ImageRequest(  
        "http://developer.android.com/images/home/aw_dac.png",  
        new Response.Listener<Bitmap>() {  
            @Override  
            public void onResponse(Bitmap response) {  
                imageView.setImageBitmap(response);  
            }  
        }, 0, 0, Config.RGB_565, new Response.ErrorListener() {  
            @Override  
            public void onErrorResponse(VolleyError error) {  
                imageView.setImageResource(R.drawable.default_image);  
            }  
        });  

ImageRequest的构造函数接收六个参数:

  • 第一个参数就是图片的URL地址,这个没什么需要解释的。
  • 第二个参数是图片请求成功的回调,这里我们把返回的Bitmap参数设置到ImageView中。
  • 第三第四个参数分别用于指定允许图片最大的宽度和高度,如果指定的网络图片的宽度或高度大于这里的最大值,则会对图片进行压缩,指定成0的话就表示不管图片有多大,都不会进行压缩。
  • 第五个参数用于指定图片的颜色属性,Bitmap.Config下的几个常量都可以在这里使用,其中ARGB_8888可以展示最好的颜色属性,每个图片像素占据4个字节的大小,而RGB_565则表示每个图片像素占据2个字节大小。
  • 第六个参数是图片请求失败的回调,这里我们当请求失败时在ImageView中显示一张默认图片。

最后将这个ImageRequest对象添加到RequestQueue里就可以了,如下所示:

mQueue.add(imageRequest);  

ImageLoader的用法

如果你觉得ImageRequest已经非常好用了,那我只能说你太容易满足了 ^_^。实际上,Volley在请求网络图片方面可以做到的还远远不止这些,而ImageLoader就是一个很好的例子。ImageLoader也可以用于加载网络上的图片,并且它的内部也是使用ImageRequest来实现的,不过ImageLoader明显要比ImageRequest更加高效,因为它不仅可以帮我们对图片进行缓存,还可以过滤掉重复的链接,避免重复发送请求。

由于ImageLoader已经不是继承自Request的了,所以它的用法也和我们之前学到的内容有所不同,总结起来大致可以分为以下四步:

  1. 创建一个RequestQueue对象。
  2. 创建一个ImageLoader对象。
  3. 获取一个ImageListener对象。
  4. 调用ImageLoader的get()方法加载网络上的图片。

新建一个ImageLoader对象,代码如下所示:

ImageLoader imageLoader = new ImageLoader(mQueue, new ImageCache() {  
    @Override  
    public void putBitmap(String url, Bitmap bitmap) {  
    }  

    @Override  
    public Bitmap getBitmap(String url) {  
        return null;  
    }  
});  

ImageLoader的构造函数接收两个参数,第一个参数就是RequestQueue对象,第二个参数是一个ImageCache对象,这里我们先new出一个空的ImageCache的实现即可。

接下来需要获取一个ImageListener对象,代码如下所示:

ImageListener listener = ImageLoader.getImageListener(imageView,  
        R.drawable.default_image, R.drawable.failed_image);  

我们通过调用ImageLoader的getImageListener()方法能够获取到一个ImageListener对象,getImageListener()方法接收三个参数,第一个参数指定用于显示图片的ImageView控件,第二个参数指定加载图片的过程中显示的图片,第三个参数指定加载图片失败的情况下显示的图片。

imageLoader.get("https://img-my.csdn.net/uploads/201404/13/1397393290_5765.jpeg",  
                listener, 200, 200);  

参考资料:
郭霖的专栏

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值