Android 数据请求之 Volley 框架

2,358 阅读6分钟

Android数据请求之Volley框架

前一篇文章(http://blog.csdn.net/zhimingshangyan/article/details/50946783)

我分享了如何搭建web服务器并且使用php编写了一个简单的接口提供程序,在接口程序中为了方便操作,我简单的使用数组的方式模拟实现了数据库的存储并且通过数组的索引值模拟了数据的查询过程。

在面试的过程中,我看到很多求职者的简历中都写了会使用volley框架,因为我们的项目中使用的是android-async-httpclient框架,于是我抱着好奇的心态搜集了一些关于volley框架的资料,在理解了这些资料的基础上我尝试了使用了一下这套框架编写了一个简单的数据请求demo。

Volley项目地址 github.com/smanikandan…

Volley的特点:

(1)JSON,图像等的异步下载;

(2)网络请求的排序(scheduling);

(3)网络请求的优先级处理;

(4)缓存;

(5)多级别取消请求;

(6)和Activity和生命周期的联动(Activity结束时同时取消所有网络请求);

接下来进入正文。先简单介绍一下我的项目文件结构


MainActivity是整个应用程序的主要视图,主要用来请求方法的调用以及请求结果的显示

FastjsonRequest使用Fastjson解析服务器返回的json数据,Fastjson是阿里的几位大神编写的一套json数据解析框架

GsonRequest使用Gson解析服务器返回的json数据,Gson是谷歌官方出的一套json数据解析框架

ObjectRequest直接接收json对象,然后根据key去获取每个key所对应的value的内容

VolleyClient用来存放请求的相关数据,比如:URL、host等服务器地址信息

module下的文件全都是根据服务器返回的json数据创建的对象,也就是MVC模式中的M(模型)

utils下的文件是图片请求要用到的两个工具类

注意:volley的所有请求都必须放到请求队列当中

一、数据请求

1、初始化请求队列

private RequestQueue requestQueue = Volley.newRequestQueue(this);

2、Volley发送Get请求

//get数据请求
private void getJson() {
    Uri.Builder builder = Uri.parse(VolleyClient.URL).buildUpon();
    builder.appendQueryParameter("a", "get_users");
    builder.appendQueryParameter("uid", "10001");
    JsonObjectRequest request = new JsonObjectRequest(Request.Method.GET, builder.toString(), null,
            new Response.Listener() {
                @Override
                public void onResponse(JSONObject jsonObject) {
                    try {
                        textview.setText("GET\n" + "Email: " + jsonObject.getJSONObject("data").getJSONObject("userInfo").getString("email"));
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
            }, new Response.ErrorListener() {
        @Override
        public void onErrorResponse(VolleyError volleyError) {
            textview.setText("Error: " + volleyError);
        }
    });
    request.setTag(TAG_REQUEST);
    requestQueue.add(request);
}

3、Volley发送post请求

//post数据请求
private void postJson1() {
    StringRequest request = new StringRequest(Request.Method.POST, VolleyClient.URL, new Response.Listener() {
        @Override
        public void onResponse(String s) {
            Gson gson = new Gson();
            Responsemod resposemod = new Responsemod();
            resposemod = gson.fromJson(s, Responsemod.class);
            textview.setText("STRING_POST\n" + "Email: " + resposemod.getData().getUserInfo().getEmail());
        }
    }, new Response.ErrorListener() {
        @Override
        public void onErrorResponse(VolleyError volleyError) {
            textview.setText("Error: " + volleyError);
        }
    }) {
        @Override
        protected Map getParams() throws AuthFailureError {
            Map params = new HashMap<>();
            params.put("a", "get_users");
            params.put("uid", "10001");
            return params;
        }
    };
    request.setTag(TAG_REQUEST);
    requestQueue.add(request);
}

4、Volley发送Gson请求

要实现Gson请求发送数据,我们必须先封装GsonRequest请求类

public class GsonRequest extends Request {
    private Gson mGson = new Gson();
    private Class clazz;
    private Map headers;
    private Map params;
    private Listener listener;

    /**
     * Make a GET request and return a parsed object from JSON.
     *
     * @param url   URL of the request to make
     * @param clazz Relevant class object, for Gson's reflection
     */
    public GsonRequest(int method,
                       String url,
                       Class clazz,
                       Listener listener,
                       ErrorListener errorListener) {
        super(method, url, errorListener);
        this.clazz = clazz;
        this.listener = listener;
        mGson = new Gson();
    }

    /**
     * Make a POST request and return a parsed object from JSON.
     *
     * @param url   URL of the request to make
     * @param clazz Relevant class object, for Gson's reflection
     */
    public GsonRequest(int method,
                       String url,
                       Class clazz,
                       Map params,
                       Listener listener,
                       ErrorListener errorListener) {

        super(method, url, errorListener);
        this.clazz = clazz;
        this.params = params;
        this.listener = listener;
        this.headers = null;
        mGson = new Gson();
    }

    @Override
    public Map getHeaders() throws AuthFailureError {
        return headers != null ? headers : super.getHeaders();
    }

    @Override
    protected Map getParams() throws AuthFailureError {
        return params;
    }

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

    @Override
    protected Response parseNetworkResponse(NetworkResponse response) {
        try {
            String json = new String(
                    response.data, HttpHeaderParser.parseCharset(response.headers));
            return Response.success(
                    mGson.fromJson(json, clazz), HttpHeaderParser.parseCacheHeaders(response));
        } catch (UnsupportedEncodingException e) {
            return Response.error(new ParseError(e));
        } catch (JsonSyntaxException e) {
            return Response.error(new ParseError(e));
        }
    }
}

然后在需要GsonRequst请求的地方调用该方法进行数据请求

private void gsonJson1() {
        sonRequest= new GsonRequest(Request.Method.POST, VolleyClient.URL, Responsemod.class,
                null, new Response.Listener() {
            @Override
            public void onResponse(Responsemod responsemod) {
                textview.setText("GSON1\n" + "Email: " + responsemod.getData().getUserInfo().getGems().get(0).getRed());
//                textview.setText("GSON1\n" + "QQ: " + responsemod.getData().getUserInfo().getQq());
            }
        }, new Response.ErrorListener() {
            @Override
            public void onErrorResponse(VolleyError volleyError) {
                textview.setText("GSON1\n" + "Error: " + volleyError.getMessage());
//                Toast.makeText(MainActivity.this, "Error: " + volleyError.getMessage(), Toast.LENGTH_LONG).show();
            }
        }) {
            @Override
            public Map getParams() throws AuthFailureError {
                Map params = new HashMap<>();
                params.put("a", "get_users");
                params.put("uid", "10002");
                return params;
            }
        };
        gsonRequest.setRetryPolicy(new DefaultRetryPolicy(1000,
                DefaultRetryPolicy.DEFAULT_MAX_RETRIES,
                DefaultRetryPolicy.DEFAULT_BACKOFF_MULT));
        gsonRequest.setTag(TAG_REQUEST);
        requestQueue.add(gsonRequest);
//        gsonRequest.cancel();
    }

5、Volley发送FastJson请求

与Gson请求相似FastJson请求也需要我们先封装FastJsonRequest请求类

public class FastJsonRequest extends Request {
    private final Class mClass;
    private final Response.Listener mListener;
    private final Map mHeaders;

    public FastJsonRequest(String url, Class cls, Response.Listener listener,
                           Response.ErrorListener errorListener) {
        this(Method.GET, url, cls, null, listener, errorListener);
    }

    public FastJsonRequest(int method, String url, Class cls, Map headers, Response.Listener listener, Response.ErrorListener errorListener) {
        super(method, url, errorListener);
        this.mClass = cls;
        this.mHeaders = headers;
        this.mListener = listener;
    }

    @Override
    public Map getHeaders() throws AuthFailureError {
        return mHeaders != null ? mHeaders : super.getHeaders();
    }

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

    @Override
    protected Response parseNetworkResponse(NetworkResponse response) {
        try {
            String json = new String(response.data, HttpHeaderParser.parseCharset(response.headers));
            return Response.success(JSON.parseObject(json, mClass),
                    HttpHeaderParser.parseCacheHeaders(response));
        } catch (UnsupportedEncodingException e) {
            return Response.error(new ParseError(e));
        }
    }
}

然后使用FastJsonRequest进行数据请求

private void fastJson() {
    FastJsonRequest fastJsonRequest = new FastJsonRequest(Request.Method.POST, VolleyClient.URL, Responsemod.class, null,
            new Response.Listener() {
                @Override
                public void onResponse(Responsemod responsemod) {
                    textview.setText("FAST\n" + "QQ: " + responsemod.getData().getUserInfo().getQq());
                }
            }, new Response.ErrorListener() {
        @Override
        public void onErrorResponse(VolleyError volleyError) {
            textview.setText("GSON1\n" + "Error: " + volleyError.getMessage());
        }
    }) {
        @Override
        protected Map getParams() throws AuthFailureError {
            Map params = new HashMap<>();
            params.put("a", "get_users");
            params.put("uid", "10001");
            return params;
        }
    };
    requestQueue.add(fastJsonRequest);
}

二、图片请求

1、图片请求

//图片请求
private void imageRequest() {
    imageRequest = new ImageRequest(imageUrl, new Response.Listener() {
        @Override
        public void onResponse(Bitmap bitmap) {
            imageView.setImageBitmap(bitmap);
        }
    }, 0, 0, Bitmap.Config.ARGB_8888, new Response.ErrorListener() {
        @Override
        public void onErrorResponse(VolleyError volleyError) {
            Toast.makeText(MainActivity.this, volleyError.toString(), Toast.LENGTH_LONG).show();
        }
    });
    imageRequest.setRetryPolicy(new DefaultRetryPolicy(5000,
            DefaultRetryPolicy.DEFAULT_MAX_RETRIES,
            DefaultRetryPolicy.DEFAULT_BACKOFF_MULT));
    requestQueue.add(imageRequest);
}

2、图片下载

private void imageDownloader() {
    ImageLoader imageLoader = new ImageLoader(requestQueue, new BitmapLruCache(max_cache_size));
    imageLoader.get(imageUrl, ImageLoader.getImageListener(imageView, R.mipmap.ic_launcher,
            android.R.drawable.ic_dialog_alert), 200, 200);
}

3、请求网络图片

private void getNetworkImage() {
    NetworkImageView imageView = (NetworkImageView) findViewById(R.id.network_imageview);
    imageView.setDefaultImageResId(R.mipmap.ic_launcher);
    imageView.setErrorImageResId(R.mipmap.ic_launcher);
    imageView.setImageUrl(imageUrl, new ImageLoader(requestQueue, new BitmapLruCache(1024 * 4)));
}

三、取消请求

1、通过request.cancel();取消某一次请求,例如:我在GsonReques的请求队列后面注释掉了gsonRequest.cancel();如果放开注释当前请求就会被取消,客户端不会收到相关请求的返回数据

2、通过循环的方式取消某一个循环队列,形式如下:

for( Request req : mRequestList) {

    req.cancel();

3、取消请求队列中的全部请求

volleyQueue.cancelAll(Object);
四、设置请求的优先级

我们可以给某个请求设置优先级,一般ImageRequests优先级被设置为LOW,诸如JsonObjectRequest和StringObjectRequest的优先级被设置为NORMAL。要想实现给不同的请求设置不同的优先级,我们需要实例化Request类并且重写setPriority和getPriority这个两个方法,下面是一段事例代码:

Priority priority;

public void setPriority(Priority priority) {

    this.priority = priority;

 * If prioirty set use it,else returned NORMAL

 * @see com.android.volley.Request#getPriority()

public Priority getPriority() {

    if( this.priority != null) {

        return priority;

    } else {

        return Priority.NORMAL; 

调用方法:

jsonRequest.setPriority(Priority.HIGH);

五、添加头部

Volley框架所有的请求头部缺省的Content-Type参数为:

  • •JsonRequest --> application/json
  • •StringRequest --> application/x-www-form-urlencoded
  • •Request --> application/x-www-form-urlencoded

如果我们想改变这种设置,就必须重写下面的方法:

public String getBodyContentType() {

   return "application/x-www-form-urlencoded; charset=UTF-8";

要是想添加头部到请求中,我们必须继承已有的请求类型并且实现getHeader()方法,事例如下:

public class MyStringRequest extends StringRequest{

    private Map headers = new HashMap();

    @Override

public Map getHeaders() throws AuthFailureError {

        return headers;

    public void setHeader(String title, String content) {

        headers.put(title, content);
六、处理错误码

Volley检查HTTP错误码并且抛出相应的错误类型。所有的错误类型继承自VolleyError,出了200(OK)和204(NO_MODIFIED),volley将其他HTTP状态码视为ERROR:

  • •TimeoutError -- ConnectionTimeout or SocketTimeout
  • •AuthFailureError -- 401 ( UNAUTHORIZED ) && 403 ( FORBIDDEN )
  • •ServerError -- 5xx
  • •ClientError -- 4xx(Created in this demo for handling all 4xx error which are treated as Client side errors)
  • •NetworkError -- No network found
  • •ParseError -- Error while converting HTTP Response to JSONObject.

七、响应缓存

Volley可以将响应缓存下来,这样就能够方便我们从缓存中获取相应数据,只需要将下面的api设置为true就可以啦!

request.setShouldCache(true);

关于Volley框架的相关知识我就讲到这里,我会把自己写的demo一起分享出来,有兴趣的小伙伴可以自己尝试一下,当然这些都只是基础应用,要熟练掌握这套框架的东西,有时间的小伙伴可以去作者的github上面阅读源码,同时也可以参照着我的文章自己动手写一下

下次,我将尝试xutils,为什么是这个而不是其他的框架呢?因为我正在使用xutils中的注解框架绑定ui视图控件,我比较感兴趣这套框架提供的ORM数据库操作框架,所以想尝试一下这套框架中的数据请求和数据库操作相关的方法。

源码地址:http://download.csdn.net/detail/zhimingshangyan/9551478