Volley使用详解

一、简介

Volley的中文翻译为“齐射、并发”,是在2013Google I/O大会上推出的一个新的网络通信框架,具有网络请求处理、小图片异步加载和缓存等功能,能够帮助APP更方便地执行网络数据操作,而且更快速高效。Volley可以说是把HttpClientUniversal-Image-Loader的优点集于了一身,既可以像HttpClient一样非常简单地进行Http通信,也可以像Universal-Image-Loader一样轻松加载网络上的图片。除了简单易用之外,Volley在性能方面也进行了大幅度的调整,它的设计目标就是非常适合去进行数据量不大但通信频繁的网络操作,而对于大数据量的网络操作比如说上传、下载文件等Volley的表现就会非常糟糕。

VolleyHttp请求在Android 2.3及以上版本中使用的是HttpURLConnection,而在Android 2.2及以下版本中使用的是HttpClient。在Android 2.2版本之前HttpClient拥有较少的Bug,因此使用它是最好的选择;而在Android 2.3版本及以后HttpURLConnection则是最佳的选择。它的API简单、体积较小,非常适用于Android项目开发。压缩和缓存机制可以有效地减少网络访问的流量,在提升速度和省电方面也起到了较大的作用。

大多数的Android应用程序都会使用Http协议来发送和接收网络数据,在Android中主要提供了两种方式来进行Http操作,分别是HttpURLConnectionHttpClient。这两种方式都支持Https协议、以流的形式进行上传和下载、配置超时时间、IPv6以及连接池等功能。

HttpClient:
DefaultHttpClientAndroidHttpClient都是HttpClient具体的实现类,它们都拥有众多的API,而且实现比较稳定,Bug数量也很少。但同时也由于HttpClientAPI数量过多,使得我们很难在不破坏兼容性的情况下对它进行升级和扩展,所以目前Android团队在提升和优化HttpClient方面的工作态度并不积极。

HttpURLConnection:
HttpURLConnection是一种多用途、轻量极的Http客户端,使用它来进行Http操作可以适用于大多数的应用程序。虽然HttpURLConnectionAPI提供的比较简单,但是这也使得我们可以更加容易地去使用和扩展它。不过在Android 2.2版本之前,HttpURLConnection一直存在着一些令人厌烦的Bug,比如说对一个可读的InputStream调用close()方法时,就有可能会导致连接池的失效。

二、特点

  1. 通信速度快、代码简单、相对比较稳定
  2. 异步执行GetPost网络请求和图片加载
  3. 网络请求可进行优先级排序处理
  4. 提供了默认的磁盘和内存等缓存
  5. 多级别取消请求,可同时取消多个网络请求
  6. 易于扩展,可自定义Request请求如GsonXml请求等
  7. 适用于数据量不大但通信频繁的网络操作
  8. 不适合大型数据的上传和下载(因为它的数据响应会全部保存在内存中)

三、权限

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

四、使用

  1. 创建RequestQueue请求队列对象
  2. 创建xxxRequest请求对象(xxx代表StringJsonObjectJsonArray等)
  3. 添加xxxRequest请求对象到RequestQueue请求队列中

五、网络请求

Volley主要提供了以下几种类型的异步网络请求:

  1. StringRequest用来接收和发送String类型的数据
  2. JsonObjectRequest用来接收和发送JsonObject类型的数据
  3. JsonArrayRequest用来接收和发送JsonArray类型的数据

请求队列:

    public static RequestQueue requestQueue;//请求队列对象
    /**
     * @Description 用于返回RequestQueue对象,如果为空则创建它
     */
    public static RequestQueue getRequestQueue() {
        if (requestQueue == null) {
            synchronized (HttpRequestUtil.class) {
                if (requestQueue == null) {
                    // 建立Volley的Http请求队列
                    requestQueue = Volley.newRequestQueue(getContext());
                }
            }
        }
        return requestQueue;
    }

StringRequest用法:

    /**
     * get 请求
     *
     * @param url      访问服务器地址
     * @param listener 自定义Http请求回调
     */
    public static void getString(String url, HttpListener listener) {
        // 创建当前请求对象
        StringRequest request = new StringRequest(url, getListener(listener), getErrorListener(listener));
        // 第一个代表超时时间:即超过20s认为超时,第三个参数代表最大重试次数,这里设置为1.0f代表如果超时则不重试
        request.setRetryPolicy(new DefaultRetryPolicy(20 * 1000, 1, 1.0f));
        // 将请求添加到队列中
        getRequestQueue().add(request);
    }

    /**
     * Http请求成功回调类
     *
     * @param listener 自定义Http请求回调
     * @return
     */
    public static Response.Listener<String> getListener(final HttpListener listener) {
        httpListener = listener;
        Response.Listener<String> mListener = new Response.Listener<String>() {
            @Override
            public void onResponse(String s) {
                httpListener.onSuccess(getReturnData(s));
            }
        };
        return mListener;
    }

    /**
     * Http请求失败回调类
     *
     * @param listener 自定义Http请求回调
     * @return
     */
    public static Response.ErrorListener getErrorListener(final HttpListener listener) {
        httpListener = listener;
        Response.ErrorListener mErrorListener = new Response.ErrorListener() {
            @Override
            public void onErrorResponse(VolleyError volleyError) {
                httpListener.onFailure(volleyError);
            }
        };
        return mErrorListener;
    }

JsonObjectRequest用法:

    /**
     * JsonObjectRequest 请求
     *
     * @param method 请求方式
     * @param url    访问服务器地址
     * @param params 请求参数
     */
    public static void requestJsonObject(int method, String url, final Map<String, String> params) {
        // 创建当前请求对象
        JsonObjectRequest request = new JsonObjectRequest(method, url, params == null ? null : new JSONObject(params), new Response.Listener<JSONObject>() {
            @Override
            public void onResponse(JSONObject jsonObject) {
                //成功响应时回调此函数
            }
        }, new Response.ErrorListener() {
            @Override
            public void onErrorResponse(VolleyError volleyError) {
                //失败响应时回调此函数
            }
        });
        // 第一个代表超时时间:即超过20s认为超时,第三个参数代表最大重试次数,这里设置为1.0f代表如果超时则不重试
        request.setRetryPolicy(new DefaultRetryPolicy(20 * 1000, 1, 1.0f));
        // 将请求添加到队列中
        getRequestQueue().add(request);
    }

JsonArrayRequest请求:

    /**
     * JsonArrayRequest 请求
     *
     * @param url 访问服务器地址
     */
    public static void requestJsonArray(String url) {
        // 创建当前请求对象
        JsonArrayRequest request = new JsonArrayRequest(url, new Response.Listener<JSONArray>() {
            @Override
            public void onResponse(JSONArray jsonArray) {
                //成功响应时回调此函数
            }
        }, new Response.ErrorListener() {
            @Override
            public void onErrorResponse(VolleyError volleyError) {
                //失败响应时回调此函数
            }
        });
        // 第一个代表超时时间:即超过20s认为超时,第三个参数代表最大重试次数,这里设置为1.0f代表如果超时则不重试
        request.setRetryPolicy(new DefaultRetryPolicy(20 * 1000, 1, 1.0f));
        // 将请求添加到队列中
        getRequestQueue().add(request);
    }

六、配置

请求设置和取消:

    // 设置请求标签
    request.setTag("tag");
    /**
     * @Description 取消网络请求
     */
    public static void cancelAll(Object tag) {
        if (tag != null) {
            getRequestQueue().cancelAll(tag);
        }
    }

请求重连和超时:

    // 第一个代表超时时间:即超过20s认为超时,第三个参数代表最大重试次数,这里设置为1.0f代表如果超时则不重试
    request.setRetryPolicy(new DefaultRetryPolicy(20 * 1000, 1, 1.0f));

请求优先级:

    // 覆写getPriority()方法
    @Override
    public Priority getPriority() {
        return Request.Priority.NORMAL;
    }

请求头部(Http头部):

    // 覆写getHeaders()方法
    @Override
    public Map<String, String> getHeaders() throws AuthFailureError {
        Map<String, String> headers = new HashMap<>();
        headers.put("cookie", "your cookie");
        return headers;
    }

请求队列重启:

    /**
     * @Description 重启当前请求队列
     */
    public static void start() {
        getRequestQueue().start();
    }

七、缓存

Volley有着强大的缓存机制用来维护请求到的缓存,这节省了不必要的网络消耗和等待时间,下面是一些关于缓存的常用方法:

从缓存中读取请求: 即先从缓存读取看是否有缓存数据,如果没有则请求网络数据

    Cache cache = getRequestQueue().getCache();
    Cache.Entry entry = cache.get(url);
    if (entry != null) {
        try {
            String data = new String(entry.data, "Utf-8");
            //处理data数据,将其转化为JSON,XML,Bitmap等等
        } catch (Exception e) {
            e.printStackTrace();
        }
    } else {
        //缓存中不存在,做网络请求
    }

缓存失效: 它并不意味着删除缓存,Volley仍将使用缓存对象,直到服务器返回新数据,一旦接收到新数据将覆盖原来的缓存

getRequestQueue().getCache().invalidate(url, true);

关闭缓存: 禁用特定Url的缓存

getRequestQueue().getCache().remove(url);

删除来自特定Url的缓存

getRequestQueue().getCache().remove(url);

删除所有缓存

getRequestQueue().getCache().clear();

八、图片加载

Volley主要提供了ImageRequestImageLoaderNetworkImageView三种图片加载方式。

ImageRequest用法:

  1. 创建一个RequestQueue对象
  2. 创建一个ImageRequest对象
  3. Request对象添加到RequestQueue里面
    /**
     * 通过ImageRequest来显示网络图片
     *
     * @param url       请求图片的地址
     * @param imageView 图片的容器ImageView
     */
    public static void setImageRequest(String url, final ImageView imageView) {
        //参数1:图片的URL地址
        //参数2:图片请求成功的回调,这里可以把返回的Bitmap参数设置到ImageView中
        //参数3和4:允许图片最大宽度和高度,如果指定网络图片的宽度或高度大于这里的最大值,则会对图片进行压缩,指定成0的话就表示不管图片有多大都不会进行压缩
        //参数5:图片的颜色属性,Bitmap.Config下的几个常量都可以在这里使用,其中ARGB_8888可以展示最好的颜色属性,每个图片像素占据4个字节的大小,而RGB_565则表示每个图片像素占据2个字节大小
        //参数6:图片请求失败的回调,这里可以设置当请求失败时在ImageView中显示一张默认图片
        ImageRequest imageRequest = new ImageRequest(url, new Response.Listener<Bitmap>() {
            @Override
            public void onResponse(Bitmap bitmap) {
                imageView.setImageBitmap(bitmap);
            }
        }, 0, 0, Bitmap.Config.RGB_565, new Response.ErrorListener() {
            @Override
            public void onErrorResponse(VolleyError volleyError) {
                imageView.setBackgroundResource(R.drawable.image_error);
            }
        });
        getRequestQueue().add(imageRequest);
    }

ImageLoader用法:

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

特点:内部是使用ImageRequest来实现的,它不仅可以对图片进行缓存,还可以过滤掉重复的链接,避免重复发送请求。

    /**
     * 通过ImageLoader来显示网络图片
     *
     * @param url       请求图片的地址
     * @param imageView 图片的容器ImageView
     */
    public static void setImageLoader(String url, ImageView imageView) {
        //参数1:RequestQueue对象
        //参数2:ImageCache对象
        ImageLoader loader = new ImageLoader(getRequestQueue(), new BitmapCache());
        //参数1:显示图片的ImageView控件
        //参数2:默认显示的图片
        //参数3:请求失败时显示的图片
        ImageLoader.ImageListener imageListener = ImageLoader.getImageListener(imageView, R.drawable.image_default, R.drawable.image_error);
        //参数1:图片的URL地址
        //参数2:ImageListener对象
        loader.get(url, imageListener);
        //参数1:图片的URL地址
        //参数2:ImageListener对象
        //参数3和4:图片允许的最大宽度和高度
        //loader.get(url, imageListener, 200, 200);
    }

NetworkImageView用法:

  1. 创建一个RequestQueue对象
  2. 创建一个ImageLoader对象
  3. 在布局文件中添加一个NetworkImageView控件
  4. 在代码中获取该控件的实例
  5. 设置要加载的图片地址

特点:NetworkImageView是一个自定义控件,它继承自ImageView,具备ImageView控件的所有功能,并且在原生的基础之上加入了加载网络图片的功能。

图片压缩:NetworkImageView是一个控件,在加载图片的时候它会自动获取自身的宽高,然后对比网络图片的宽高,再决定是否需要对图片进行压缩。也就是说,压缩过程是在内部完全自动化的,并不需要我们关心,NetworkImageView会始终呈现给我们一张大小刚刚好的网络图片,不会多占用任何一点内存。

    /**
     * 通过NetWorkImageView来显示网络图片
     *
     * @param url              请求图片的地址
     * @param netWorkImageView 图片的容器NetworkImageView
     */
    public static void setNetWorkImageView(String url, NetworkImageView netWorkImageView) {
        ImageLoader loader = new ImageLoader(getRequestQueue(), new BitmapCache());
        netWorkImageView.setDefaultImageResId(R.drawable.image_default);
        netWorkImageView.setErrorImageResId(R.drawable.image_error);
        netWorkImageView.setImageUrl(url, loader);
    }

九、自定义Request

Volley提供了非常好的扩展机制,使得我们可以很轻松地自定义任意类型的Request来满足不同的数据格式解析。

自定义XMLRequest:

package com.wiggins.volley.http;

import com.android.volley.NetworkResponse;
import com.android.volley.ParseError;
import com.android.volley.Request;
import com.android.volley.Response;
import com.android.volley.Response.ErrorListener;
import com.android.volley.Response.Listener;
import com.android.volley.toolbox.HttpHeaderParser;

import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
import org.xmlpull.v1.XmlPullParserFactory;

import java.io.StringReader;
import java.io.UnsupportedEncodingException;

/**
 * @Description 自定义XMLRequest用于请求XML格式的数据
 * @Author 一花一世界
 */
public class XMLRequest extends Request<XmlPullParser> {

    private final Listener<XmlPullParser> mListener;

    public XMLRequest(int method, String url, Listener<XmlPullParser> listener, ErrorListener errorListener) {
        super(method, url, errorListener);
        mListener = listener;
    }

    public XMLRequest(String url, Listener<XmlPullParser> listener, ErrorListener errorListener) {
        this(Method.GET, url, listener, errorListener);
    }

    @Override
    protected void deliverResponse(XmlPullParser response) {
        mListener.onResponse(response);
    }

    @Override
    protected Response<XmlPullParser> parseNetworkResponse(NetworkResponse response) {
        try {
            String xmlString = new String(response.data, "UTF-8");
            XmlPullParserFactory factory = XmlPullParserFactory.newInstance();
            XmlPullParser xmlPullParser = factory.newPullParser();
            xmlPullParser.setInput(new StringReader(xmlString));
            return Response.success(xmlPullParser, HttpHeaderParser.parseCacheHeaders(response));
        } catch (UnsupportedEncodingException e) {
            return Response.error(new ParseError(e));
        } catch (XmlPullParserException e) {
            return Response.error(new ParseError(e));
        }
    }
}

自定义GsonRequest:

package com.wiggins.volley.http;

import com.android.volley.NetworkResponse;
import com.android.volley.ParseError;
import com.android.volley.Request;
import com.android.volley.Response;
import com.android.volley.Response.ErrorListener;
import com.android.volley.Response.Listener;
import com.android.volley.toolbox.HttpHeaderParser;
import com.google.gson.Gson;

import java.io.UnsupportedEncodingException;

/**
 * @Description 自定义GsonRequest<T>用于使用GSON来解析数据
 * @Author 一花一世界
 */
public class GsonRequest<T> extends Request<T> {

    private final Listener<T> mListener;
    private Gson mGson;
    private Class<T> mClass;

    public GsonRequest(int method, String url, Class<T> clazz, Listener<T> listener, ErrorListener errorListener) {
        super(method, url, errorListener);
        mGson = new Gson();
        mClass = clazz;
        mListener = listener;
    }

    public GsonRequest(String url, Class<T> clazz, Listener<T> listener, ErrorListener errorListener) {
        this(Method.GET, url, clazz, listener, errorListener);
    }

    @Override
    protected void deliverResponse(T response) {
        mListener.onResponse(response);
    }

    @Override
    protected Response<T> parseNetworkResponse(NetworkResponse response) {
        try {
            String jsonString = new String(response.data, "UTF-8");
            return Response.success(mGson.fromJson(jsonString, mClass),
                    HttpHeaderParser.parseCacheHeaders(response));
        } catch (UnsupportedEncodingException e) {
            return Response.error(new ParseError(e));
        }
    }
}

项目地址 ☞ 传送门

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值