欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

android开发,volley的二次封装和使用

程序员文章站 2024-03-15 19:20:30
...

先简单介绍一下。Android SDK中提供了HttpClient 和 HttpUrlConnection两种方式用来处理网络操作,但应用起来比较繁琐,需要我们编写大量的代码处理很多东西:缓存,Header等等;

而Volley框架就是为解决这些而生的,它与2013年Google I/O大会上被提出:使得Android应用网络操作更方便更快捷;抽象了底层Http Client等实现的细节,让开发者更专注与产生RESTful Request。另外,Volley在不同的线程上异步执行所有请求而避免了阻塞主线程。

android开发,volley的二次封装和使用

Volley到底有哪些特点呢?

  1. 自动调度网络请求
  2. 多个并发的网络连接
  3. 通过使用标准的HTTP缓存机制保持磁盘和内存响应的一致
  4. 支持请求优先级
  5. 支持取消请求的强大API,可以取消单个请求或多个
  6. 易于定制
  7. 健壮性:便于正确的更新UI和获取数据
  8. 包含调试和追踪工具

好,废话结束了。一起看看怎么使用volley吧。volley本身使用是比较容易的,但我们做项目过程中往往需要再封装一下,以便于更好的统一使用,本文就是对volley的二次封装,便于开发过程中调用。你也可以根据你的需要进行一些改造。需要注意一点的是,volley只适合数据量比较小,比较频繁的请求。对数据量比较大的,比如下载文件等不太合适。


首先使用volley需要导入相关的jar包,只需要一个jar而已,可以到maven下载:http://mvnrepository.com/artifact/com.mcxiaoke.volley/library/1.0.19


在你的android工程的  values/strings.xml 文件添加下面几个元素,是用来提示用的:

  <string name="no_internet">无网络连接~!</string>
    <string name="generic_server_down">连接服务器失败~!</string>
    <string name="generic_error">网络异常,请稍后再试~!</string>

下面看看3个关键的类,直接放到工程里面就可以使用,里面有详细的注释

Volley异常帮助类  

package com.kokjuis.travel.volley;

import java.util.HashMap;
import java.util.Map;

import android.content.Context;

import com.android.volley.AuthFailureError;
import com.android.volley.NetworkError;
import com.android.volley.NetworkResponse;
import com.android.volley.NoConnectionError;
import com.android.volley.ServerError;
import com.android.volley.TimeoutError;
import com.android.volley.VolleyError;
import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
import com.kokjuis.travel.R;

//以下是Volley的异常列表:
//AuthFailureError:如果在做一个HTTP的身份验证,可能会发生这个错误。
//NetworkError:Socket关闭,服务器宕机,DNS错误都会产生这个错误。
//NoConnectionError:和NetworkError类似,这个是客户端没有网络连接。
//ParseError:在使用JsonObjectRequest或JsonArrayRequest时,如果接收到的JSON是畸形,会产生异常。
//SERVERERROR:服务器的响应的一个错误,最有可能的4xx或5xx HTTP状态代码。
//TimeoutError:Socket超时,服务器太忙或网络延迟会产生这个异常。默认情况下,Volley的超时时间为2.5秒。如果得到这个错误可以使用RetryPolicy。


/**
 * volley异常帮助类
 *
 * @author:gj
 * @date: 2016/5/17
 * @time: 15:05
 **/
public class VolleyErrorHelper {

    /**
     * Returns appropriate message which is to be displayed to the user against
     * the specified error object.
     *
     * @param error
     * @param context
     * @return
     */
    public static String getMessage(Object error, Context context) {
        if (error instanceof TimeoutError) {
            return context.getResources().getString(
                    R.string.generic_server_down);
        } else if (isServerProblem(error)) {
            return handleServerError(error, context);
        } else if (isNetworkProblem(error)) {
            return context.getResources().getString(R.string.no_internet);
        }
        return context.getResources().getString(R.string.generic_error);
    }

    /**
     * Determines whether the error is related to network
     *
     * @param error
     * @return
     */
    private static boolean isNetworkProblem(Object error) {
        return (error instanceof NetworkError)
                || (error instanceof NoConnectionError);
    }

    /**
     * Determines whether the error is related to server
     *
     * @param error
     * @return
     */
    private static boolean isServerProblem(Object error) {
        return (error instanceof ServerError)
                || (error instanceof AuthFailureError);
    }

    /**
     * Handles the server error, tries to determine whether to show a stock
     * message or to show a message retrieved from the server.
     *
     * @param err
     * @param context
     * @return
     */
    private static String handleServerError(Object err, Context context) {
        VolleyError error = (VolleyError) err;

        NetworkResponse response = error.networkResponse;

        if (response != null) {
            switch (response.statusCode) {
                case 404:
                case 422:
                case 401:
                    try {
                        // server might return error like this { "error":
                        // "Some error occured" }
                        // Use "Gson" to parse the result
                        HashMap<String, String> result = new Gson().fromJson(
                                new String(response.data),
                                new TypeToken<Map<String, String>>() {
                                }.getType());

                        if (result != null && result.containsKey("error")) {
                            return result.get("error");
                        }

                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                    // invalid request
                    return error.getMessage();

                default:
                    return context.getResources().getString(
                            R.string.generic_server_down);
            }
        }
        return context.getResources().getString(R.string.generic_error);
    }
}


volley请求类

package com.kokjuis.travel.volley;

import android.util.Log;

import com.android.volley.AuthFailureError;
import com.android.volley.DefaultRetryPolicy;
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.Listener;
import com.android.volley.RetryPolicy;
import com.android.volley.toolbox.HttpHeaderParser;
import com.kokjuis.travel.comm.MyApplication;
import com.kokjuis.travel.utils.GsonUtil;
import com.kokjuis.travel.utils.RsaEncryptUtil;

import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.util.HashMap;
import java.util.Map;

/**
 * 类描述: 创建人:kokJuis 创建时间:2016/3/8 14:07 修改备注:
 * <p>
 * VolleyRequest vr=new VolleyRequest(Request.Method.POST,
 * WebLinksUtil.login,params,new Response.Listener() {
 *
 * @Override public void onResponse(Object o) {
 * <p>
 * Log.v("--->>>>-----",o.toString()); } }, new
 * Response.ErrorListener() {
 * @Override public void onErrorResponse(VolleyError volleyError) {
 * Log.v("--->>>>-----",volleyError.getMessage()); } });
 * <p>
 * VolleyUtil.getVolleyUtil(this).addToRequestQueue(vr,TAG);
 */
public class VolleyRequest extends Request<String> {

    private static final String TAG = "VolleyRequest";

    //请求监听
    private final Listener<Object> listener;
    //保存请求参数
    private static Map<String, String> params;


    // 构造方法
    private VolleyRequest(int method, String url,
                          Response.Listener<Object> listener,
                          Response.ErrorListener errorListener) {
        super(method, url, errorListener);
        this.listener = listener;
    }


    /**
     * post请求
     *
     * @author:gj
     * @date: 2016/5/17
     * @time: 15:13
     **/
    public static VolleyRequest post(String url, Map<String, String> params,
                                     Response.Listener<Object> listener,
                                     Response.ErrorListener errorListener) {

        //下面只是打印出完整的URL,便于调试
        if (params != null) {
            Log.v(TAG, "params:" + params);
            String str = "";
            for (Map.Entry<String, String> entry : params.entrySet()) {
                str += entry.getKey() + "=" + entry.getValue() + "&";
            }
            String tmp = url + "?"
                    + str.substring(0, str.length()-1);
            Log.v(TAG, "url:" + tmp);
           
                //把参数赋值
                VolleyRequest.params = data;
            
        }
        return new VolleyRequest(Method.POST, url, listener, errorListener);
    }

    /**
     * get请求
     *
     * @author:gj
     * @date: 2016/5/17
     * @time: 15:13
     **/
    public static VolleyRequest get(String url, Map<String, String> params,
                                    Response.Listener<Object> listener,
                                    Response.ErrorListener errorListener) {

        //下面只是打印出完整的URL,便于调试
        if (params != null) {
            Log.v(TAG, "params:" + params);
            String str = "";
            for (Map.Entry<String, String> entry : params.entrySet()) {
                str += entry.getKey() + "=" + entry.getValue() + "&";
            }
            url += "?"
                    + str.substring(0, str.length()-1);
            Log.v(TAG, "url:" + url);

          //这里可以根据你的要求改造
        }
        return new VolleyRequest(Method.GET, url, listener, errorListener);
    }


    /**
     * 请求返回
     *
     * @author:gj
     * @date: 2017/5/17
     * @time: 15:24
     **/
    @Override
    protected Response<String> parseNetworkResponse(
            NetworkResponse networkResponse) {
        String parsed;

        try {
            //这里可以获取返回的header信息,可以把想要的东西提取
            Map<String, String> responseHeaders = networkResponse.headers;
            String Token = responseHeaders.get("Token");
            if (Token != null) {
                Log.v(TAG, "Token:" + Token);
            }

            parsed = new String(networkResponse.data,
                    HttpHeaderParser.parseCharset(networkResponse.headers));
            return Response.success(parsed,
                    HttpHeaderParser.parseCacheHeaders(networkResponse));

        } catch (UnsupportedEncodingException e) {
            // parsed = new String(networkResponse.data);
            return Response.error(new ParseError(e));
        } catch (Exception e) {
            return Response.error(new ParseError(e));
        }
    }


    /**
     * 监听返回
     *
     * @author:gj
     * @date: 2017/5/17
     * @time: 15:20
     **/
    @Override
    protected void deliverResponse(String response) {
        listener.onResponse(response);
    }


    /**
     * 请求设置参数
     *
     * @author:gj
     * @date: 2017/5/17
     * @time: 15:20
     **/
    @Override
    protected Map<String, String> getParams() throws AuthFailureError {
        return params == null ? super.getParams() : params;
    }

    /**
     * 设置请求头
     *
     * @author:gj
     * @date: 2017/5/17
     * @time: 15:20
     **/
    @Override
    public Map<String, String> getHeaders() throws AuthFailureError {

        //在这个方法里面,可以设置请求头的参数,比如Charset,Content-Type,也可以设置一些你想要的值
        HashMap<String, String> localHashMap = new HashMap<String, String>();
        localHashMap.put("Charset", "UTF-8");
        localHashMap.put("Content-Type", "application/x-www-form-urlencoded");
        // localHashMap.put("Accept-Encoding", "gzip,deflate");

        //设置请求的token
        localHashMap.put("Token", "");

        return localHashMap;
    }

    /**
     * 设置请求超时时间
     *
     * @author:gj
     * @date: 2017/5/17
     * @time: 15:22
     **/
    @Override
    public RetryPolicy getRetryPolicy() {
        // 设置超时时间为5秒。
        RetryPolicy retryPolicy = new DefaultRetryPolicy(5000, 0,
                DefaultRetryPolicy.DEFAULT_BACKOFF_MULT);
        return retryPolicy;
    }

    @Override
    public void setRetryPolicy(RetryPolicy retryPolicy) {
        RetryPolicy Policy = new DefaultRetryPolicy(5000, 0,
                DefaultRetryPolicy.DEFAULT_BACKOFF_MULT);
        super.setRetryPolicy(Policy);
    }
}


volley请求工具类

package com.kokjuis.travel.volley;

import android.content.Context;
import android.graphics.Bitmap;
import android.text.TextUtils;
import android.util.LruCache;

import com.android.volley.Request;
import com.android.volley.RequestQueue;
import com.android.volley.toolbox.ImageLoader;
import com.android.volley.toolbox.Volley;

/**
 * 创建人:kokJuis 创建时间:2016/3/8 14:57 备注:
 */
public class VolleyUtil {

    public static final String TAG = "VolleyUtil";

    private static VolleyUtil volleyUti;
    private RequestQueue mRequestQueue;
    private ImageLoader mImageLoader;
    private Context mContext;

    /**
     * 单例模式。
     *
     * @param context
     */
    private VolleyUtil(Context context) {
        this.mContext = context;
        mRequestQueue = getRequestQueue();
        mImageLoader = new ImageLoader(mRequestQueue,
                new ImageLoader.ImageCache() {
                    private final LruCache<String, Bitmap> cache = new LruCache<String, Bitmap>(
                            20);

                    @Override
                    public Bitmap getBitmap(String url) {
                        return cache.get(url);
                    }

                    @Override
                    public void putBitmap(String url, Bitmap bitmap) {
                        cache.put(url, bitmap);
                    }
                });
    }

    public static synchronized VolleyUtil getVolleyUtil(Context context) {
        if (volleyUti == null) {
            volleyUti = new VolleyUtil(context);
        }
        return volleyUti;
    }

    // 获取一个请求队列
    public RequestQueue getRequestQueue() {
        if (mRequestQueue == null) {
            mRequestQueue = Volley.newRequestQueue(mContext
                    .getApplicationContext());
        }
        return mRequestQueue;
    }

    // 把请求添加到队列里面
    public <T> void addToRequestQueue(Request<T> req, String tag) {
        // 设置一个标记,便于取消队列里的请求
        req.setTag(TextUtils.isEmpty(tag) ? TAG : tag);
        getRequestQueue().add(req);

    }


    // 取消指定请求
    public void cancelRequest(String tag) {
        if (mRequestQueue != null) {
            mRequestQueue.cancelAll(tag);
        }
    }

    public ImageLoader getImageLoader() {
        return mImageLoader;
    }

}


使用:

 private void getUserData(String account) {

        Map<String, String> params = new HashMap<String, String>();
        params.put("account", account);
	//创建一个get请求
        VolleyRequest vr = VolleyRequest.get(
                ApiList.findByAccounts_api, params,
                new Listener<Object>() {
                    @Override
                    public void onResponse(Object arg0) {
                        if (arg0 != null) {
			//请求成功
                            Log.v(TAG, arg0.toString());

                        }
                    }
                }, new ErrorListener() {

                    @Override
                    public void onErrorResponse(VolleyError arg0) {
                        Log.e(TAG, arg0.getMessage());//请求失败,打印失败信息
                    }

                });
	//把请求添加到请求队列才会真正的请求网络,第一参数就是创建的请求,第二个是请求的标记,可以通过这个标记取消请求
        VolleyUtil.getVolleyUtil(this).addToRequestQueue(vr, TAG);

    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
	//取消请求
        VolleyUtil.getVolleyUtil(this).cancelRequest(TAG);
    }