Volley网络请求框架使用

一、前言:

Volley是Google官方出的一套小而巧的异步请求库,该框架封装的扩展性很强,支持HttpClient、HttpUrlConnection,甚至支持OkHttp,而且Volley里面也封装了ImageLoader,所以如果你愿意你甚至不需要使用图片加载框架,不过这块功能没有一些专门的图片加载框架强大,对于简单的需求可以使用,对于稍复杂点的需求还是需要用到专门的图片加载框架。

Volley也有缺陷,比如不支持post大数据,所以不适合上传文件。不过Volley设计的初衷本身也就是为频繁的、数据量小的网络请求而生!

1. Volley网络请求队列

Volley 请求网络都是基于请求队列的,开发者只要把请求放在请求队列中就可以了,请求队列会依次进行请求。一般情况下,一个应用程序如果网络请求不是特别的频繁,完全可以只有一个请求队列(对应 Application);如果网络请求非常多或者有其他情况,则可以是一个 Activity 对应一个网络请求队列,这就要看具体情况了。

示例:

RequestQueue queue = Volley.newRequestQueue(getApplicationContext());

网络请求权限一定不要忘记:

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

二、 基本使用:

1.volley依赖

 //volley依赖
implementation 'com.mcxiaoke.volley:library:1.0.19'
 //gson依赖
compile 'com.google.code.gson:gson:2.7'
//butterknife,配置下面 两行
implementation 'com.jakewharton:butterknife:8.5.1'
annotationProcessor 'com.jakewharton:butterknife-compiler:8.5.1'

2.RequestQueue在 Application 中初始化一次

public class MyApplication extends Application {
    public static RequestQueue queue;


    @Override
    public void onCreate() {
        super.onCreate();
        queue = Volley.newRequestQueue(getApplicationContext());
    }

    /**
     * 提供全局变量,如果使用 VolleyUtils 类,这里就不用写了
     * 创建请求队列对象,通常情况下,一个类中(或者说一个工程中)保持 始终使用同一个RequestQueue对象即可
     * @return
     */
    public static RequestQueue getHttpQueues() {
        return queue;
    }
}

3. StringRequest 中GET 请求

    /**
     * get 请求
     */
    private void getRequest() {

        String url = "http://apis.juhe.cn/mobile/get?phone=18856907654&key=5778e9d9cf089fc3b093b162036fc0e1";


        /**
         * 1. int 类型 用于指定请求的方式(如GET或者POST)
         * 2. String类型 用于指定网络请求要连接的网址
         * 3. Listener类型 ,接收网络响应的接口,即只要得到本次请求对应的返回结果
         * 就会运行此接口中的onResponse方法
         * 4: ErrorListener类型, 用于接收当网络请求的过程中一旦发生了什么错误,
         * 就会调用本接口中的onErrorResponse方法
         * */
        StringRequest stringRequest = new StringRequest(StringRequest.Method.GET, url, new Response.Listener<String>() {
            @Override
            public void onResponse(String response) {
                Log.d("LUO", "========" + response);
            }
        }, new Response.ErrorListener() {
            @Override
            public void onErrorResponse(VolleyError error) {
                Log.d("LUO", "========" + error.getMessage());
            }
        });

        //三,给请求对象设置tag标识
        stringRequest.setTag("get");
        //四,将请求添加到请求队列中,执行网络请求
        MyApplication.getHttpQueues().add(stringRequest);
       //不要调用,看下方注意
        //MyApplication.getHttpQueues().start();
    }

注意:

//MyApplication.getHttpQueues().start();
建议不要手动调用 RequestQueue 的 start() 方法,引起的问题“经常会报com.android.volley.NoConnectionError: java.io.InterruptedIOException”,然后就内容加载失败。。。

因为在 Volley.newRequestQueue() 方法中,已经调用了 start() 方法。

看源码示例:

public static RequestQueue newRequestQueue(Context context, HttpStack stack, int maxDiskCacheBytes) {
        File cacheDir = new File(context.getCacheDir(), DEFAULT_CACHE_DIR);

        String userAgent = "volley/0";
        try {
            String packageName = context.getPackageName();
            PackageInfo info = context.getPackageManager().getPackageInfo(packageName, 0);
            userAgent = packageName + "/" + info.versionCode;
        } catch (NameNotFoundException e) {
        }

        if (stack == null) {
            if (Build.VERSION.SDK_INT >= 9) {
                stack = new HurlStack();
            } else {
                // Prior to Gingerbread, HttpUrlConnection was unreliable.
                // See: http://android-developers.blogspot.com/2011/09/androids-http-clients.html
                stack = new HttpClientStack(AndroidHttpClient.newInstance(userAgent));
            }
        }

        Network network = new BasicNetwork(stack);
        
        RequestQueue queue;
        if (maxDiskCacheBytes <= -1)
        {
            // No maximum size specified
            queue = new RequestQueue(new DiskBasedCache(cacheDir), network);
        }
        else
        {
            // Disk cache size specified
            queue = new RequestQueue(new DiskBasedCache(cacheDir, maxDiskCacheBytes), network);
        }
        //这里已经启动了,不需要请求中再次调用
        queue.start();

        return queue;
    }

3. StringRequest 中 POST请求

 /**
     * post 请求
     */
    private void postRequest() {

        RequestQueue queue = Volley.newRequestQueue(this);
        String postUrl = "http://apis.juhe.cn/mobile/get";

        StringRequest stringRequest = new StringRequest(StringRequest.Method.POST, postUrl, new Response.Listener<String>() {
            @Override
            public void onResponse(String response) {
                Log.d("LUO", "========" + response);

            }
        }, new Response.ErrorListener() {
            @Override
            public void onErrorResponse(VolleyError error) {
                Log.d("LUO", "========" + error.getMessage());
            }
        }) {
            /**
             * Post请求和Get请求的使用步骤上的区别在于请求条件的指定
             * 必须在StringRequest对象的后面添加{},并且
             * 在{}内重写getParams方法,该方法的返回值就是所有的请求条件
             * */
            @Override
            protected Map<String, String> getParams() throws AuthFailureError {
                //将请求条件封装到map对象中
                Map<String, String> map = new HashMap<>();
                map.put("phone", "18856907654");
                map.put("key", "5778e9d9cf089fc3b093b162036fc0e1");
                return map;
            }
        };

        //三,给请求对象设置tag标识
        stringRequest.setTag("get");
        //四,将请求添加到请求队列中,执行网络请求
        MyApplication.getHttpQueues().add(stringRequest);
    }

4.JSONObject网络请求

 private void jsonRequest() {
        String postUrl = "http://apis.juhe.cn/mobile/get";
        Map<String, String> map = new HashMap<>();
        map.put("phone", "18856907654");
        map.put("key", "5778e9d9cf089fc3b093b162036fc0e1");

        String json = new Gson().toJson(map);
        JsonObjectRequest jsonObjectRequest = new JsonObjectRequest(Request.Method.POST,
                postUrl,json, new Response.Listener<JSONObject>() {
            @Override
            public void onResponse(JSONObject response) {
                Log.d("LUO", "========" + response);
            }
        },new Response.ErrorListener(){

            @Override
            public void onErrorResponse(VolleyError error) {
                Log.d("LUO", "========" + error.getMessage());
            }
        });

        MyApplication.getHttpQueues().add(jsonObjectRequest);
    }

5.下载单张图片

/**
     * 下载单张图片
     */
    private void singlePhoto() {

        ImageRequest imageRequest = new ImageRequest(
                "https://ss1.bdstatic.com/70cFvXSh_Q1YnxGkpoWK1HF6hhy/it/u=2019270811,1269730008&fm=27&gp=0.jpg", //对应图片的下载地址
                new Response.Listener<Bitmap>() {
                    @Override
                    public void onResponse(Bitmap response) {
                        Log.d("LUO", "========" + response);
                        ivIcon.setImageBitmap(response);
                    }
                }, 200, 200,// 指定下载后图片的最大宽高
                ImageView.ScaleType.FIT_XY,//指定图片的缩放模式
                Bitmap.Config.ARGB_8888,//指定图片的编码格式
                new Response.ErrorListener() {
                    @Override
                    public void onErrorResponse(VolleyError error) {
                        Log.d("LUO", "========" + error.getMessage());
                    }
                });
        MyApplication.getHttpQueues().add(imageRequest);
    }

6.与Avctivity生命周期联动(注意啊)

其实就是在Activity退出时候或销毁时候,取消对应的网络请求,避免网络请求在后台浪费资源,所以,我们一般在onStop()方法中通过之前设置的Tag取消网络请求:

 @Override
    protected void onDestroy() {
        super.onDestroy();
        //通过Tag标签取消请求队列中对应的全部请求
        MyApplication.getHttpQueues().cancelAll(tag);
    }

三、封装使用:

1.VolleyUtils类

public class VolleyUtils {
    private static RequestQueue mQueue;
    private ImageLoader mLoader;
    private ImageLoader.ImageCache mCache;
    private static VolleyUtils mInstance;

    /**
     * 1.构造方法私有化
     * @param context
     */
    private VolleyUtils(Context context) {
        //做一些事情
        mQueue = Volley.newRequestQueue(context);
        mCache = new MyImageCache();
        mLoader = new ImageLoader(mQueue, mCache);
    }

    public RequestQueue getQueue() {
        return mQueue;
    }

    public ImageLoader getLoader() {
        return mLoader;
    }


    /**
     * 2.提供一个静态方法,返回一个当前类
     * @param context
     * @return
     */
    public static VolleyUtils create(Context context) {
        if (mInstance == null) {
            synchronized (VolleyUtils.class) {
                if (mInstance == null) {
                    mInstance = new VolleyUtils(context);
                }
            }
        }
        return mInstance;
    }


    public <T> void get(String url, final Class<T> clazz, final OnResponse<T> listener) {

        HashMap<String, String> map = new HashMap<>();
        listener.OnMap(map);
        String param = prepareParam(map);
        if (param.trim().length() >= 1) {
            url += "?" + param;
        }
        Log.e("Volley", "urlResult---->" + url);
        StringRequest stringRequest = new StringRequest(StringRequest.Method.GET, url, new Response.Listener<String>() {
            @Override
            public void onResponse(String response) {
                Log.e("Volley", "response-->" + response);
                Gson gson = new Gson();
                listener.onSuccess(gson.fromJson(response, clazz));
            }
        }, new Response.ErrorListener() {
            @Override
            public void onErrorResponse(VolleyError error) {
                Log.e("Volley", "response-->" + error.getMessage());
                listener.onError(error.getMessage());
            }
        });

        mQueue.add(stringRequest);
    }


    private static String prepareParam(Map<String, String> paramMap) {
        StringBuilder sb = new StringBuilder();
        if (paramMap.isEmpty()) {
            return "";
        } else {
            for (String key : paramMap.keySet()) {
                String value =  paramMap.get(key);
                if (sb.length() < 1) {
                    sb.append(key).append("=").append(value);
                } else {
                    sb.append("&").append(key).append("=").append(value);
                }
            }
            return sb.toString();
        }
    }


    public <T> void post(String url, final Class<T> clazz, final OnResponse<T> listener) {
        StringRequest stringRequest = new StringRequest(StringRequest.Method.POST, url, new Response.Listener<String>() {
            @Override
            public void onResponse(String response) {
                Log.e("Volley", "response-->" + response);
                Gson gson = new Gson();
                listener.onSuccess(gson.fromJson(response, clazz));
            }
        }, new Response.ErrorListener() {
            @Override
            public void onErrorResponse(VolleyError error) {
                Log.e("Volley", "response-->" + error.getMessage());
                listener.onError(error.getMessage());
            }
        }) {
            /**
             * Post请求和Get请求的使用步骤上的区别在于请求条件的指定
             * 必须在StringRequest对象的后面添加{},并且
             * 在{}内重写getParams方法,该方法的返回值就是所有的请求条件
             * */
            @Override
            protected Map<String, String> getParams() throws AuthFailureError {
                //将请求条件封装到map对象中
                Map<String, String> map = new HashMap<>();
                listener.OnMap(map);
                return map;
            }
        };
        mQueue.add(stringRequest);
    }


    public void loadImg(String url, ImageView view, int maxWidth, int maxHeight, int defaultImageResId, int errorImageResId) {
        mLoader.get(url, //图片的下载路径
                /**
                 * 通过getImageListener方法获取ImageListener接口对象
                 * 参数1: 图片下载完成后,由哪个控件显示图片
                 * 参数2: 设置图片下载过程中显示的默认图片
                 * 参数3: 设置一旦图片下载出错,就显示出错提示图片
                 * */
                ImageLoader.getImageListener(view, defaultImageResId, errorImageResId),
                maxWidth, maxHeight, //图片的最大宽高 指定成0的话就表示不管图片有多大
                ImageView.ScaleType.FIT_XY //图片的缩放模式
        );
    }

    public void loadImg(String url, ImageView view) {
        mLoader.get(url, //图片的下载路径
                ImageLoader.getImageListener(view, R.mipmap.ic_launcher, R.mipmap.ic_launcher),
                0, 0, //图片的最大宽高 指定成0的话就表示不管图片有多大
                ImageView.ScaleType.FIT_XY //图片的缩放模式
        );
    }

    public void loadImg(String url, ImageView view, int defaultImageResId, int errorImageResId) {
        mLoader.get(url, //图片的下载路径
                ImageLoader.getImageListener(view, defaultImageResId, errorImageResId),
                0, 0, //图片的最大宽高 指定成0的话就表示不管图片有多大
                ImageView.ScaleType.FIT_XY //图片的缩放模式
        );
    }

    /**
     * 分配一定内存空间,专门存取图片,一般为内存大小的1/8
     */
    private class MyImageCache implements ImageLoader.ImageCache {

        private LruCache<String, Bitmap> mCache;

        private MyImageCache() {
            //分配最大内存空间的1/8
            long maxMemory = Runtime.getRuntime().maxMemory() / 8;
            mCache = new LruCache<String, Bitmap>((int) maxMemory) {
                @Override
                protected int sizeOf(String key, Bitmap value) {
                    //得到当前图片的大小
                    return value.getByteCount();
                }
            };
        }

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

        @Override
        public void putBitmap(String url, Bitmap bitmap) {
            if (getBitmap(url) == null)
                mCache.put(url, bitmap);
        }
    }

    /**
     * 自定义的类型
     * @param <T>
     */
    public class GsonRequest<T> extends Request<T> {
        private Response.Listener<T> mListener;
        private Gson mGson;
        private Class<T> mClazz;

        private GsonRequest(int method, String url, Response.Listener<T> listener, Response.ErrorListener errorListenerlistener, Class<T> clazz) {
            super(method, url, errorListenerlistener);
            this.mListener = listener;
            mGson = new Gson();
            this.mClazz = clazz;
        }

        @Override
        protected Response<T> parseNetworkResponse(NetworkResponse response) {
            String parsed;
            try {
                parsed = new String(response.data, HttpHeaderParser.parseCharset(response.headers));
                Log.e("Volley", "服务器返回JSON------>" + parsed);
                return Response.success(mGson.fromJson(parsed, mClazz), HttpHeaderParser.parseCacheHeaders(response));
            } catch (UnsupportedEncodingException e) {
                return Response.error(new VolleyError(e));
            }
        }

        @Override
        protected void deliverResponse(T response) {
            if (mListener != null) {
                mListener.onResponse(response);
            }
        }

        @Override
        protected void onFinish() {
            super.onFinish();
            mListener = null;
        }
    }

    public interface OnResponse<T> {

        void OnMap(Map<String, String> map);

        void onSuccess(T response);

        void onError(String error);
    }
}

2.PhoneBean类

public class PhoneBean {

    /**
     * resultcode : 200
     * reason : Return Successd!
     * result : {"province":"安徽","city":"合肥","areacode":"0551","zip":"230000","company":"移动","card":""}
     * error_code : 0
     */

    private String resultcode;
    private String reason;
    private ResultBean result;
    private int error_code;

    public String getResultcode() {
        return resultcode;
    }

    public void setResultcode(String resultcode) {
        this.resultcode = resultcode;
    }

    public String getReason() {
        return reason;
    }

    public void setReason(String reason) {
        this.reason = reason;
    }

    public ResultBean getResult() {
        return result;
    }

    public void setResult(ResultBean result) {
        this.result = result;
    }

    public int getError_code() {
        return error_code;
    }

    public void setError_code(int error_code) {
        this.error_code = error_code;
    }

    public static class ResultBean {
        /**
         * province : 安徽
         * city : 合肥
         * areacode : 0551
         * zip : 230000
         * company : 移动
         * card :
         */

        private String province;
        private String city;
        private String areacode;
        private String zip;
        private String company;
        private String card;

        public String getProvince() {
            return province;
        }

        public void setProvince(String province) {
            this.province = province;
        }

        public String getCity() {
            return city;
        }

        public void setCity(String city) {
            this.city = city;
        }

        public String getAreacode() {
            return areacode;
        }

        public void setAreacode(String areacode) {
            this.areacode = areacode;
        }

        public String getZip() {
            return zip;
        }

        public void setZip(String zip) {
            this.zip = zip;
        }

        public String getCompany() {
            return company;
        }

        public void setCompany(String company) {
            this.company = company;
        }

        public String getCard() {
            return card;
        }

        public void setCard(String card) {
            this.card = card;
        }
    }
}

3.直接调用:

public class TwoActivity extends Activity{

    private ImageView img;
    String urlStr = "http://apis.juhe.cn/mobile/get";

    String imgUrl = "https://ss1.bdstatic.com/70cFvXSh_Q1YnxGkpoWK1HF6hhy/it/u=1263067444,118499721&fm=27&gp=0.jpg";
    private TextView textView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_two);
        img = findViewById(R.id.img);
        textView = findViewById(R.id.text);
    }

    public void btnGet(View view) {

        VolleyUtils.create(this)
                .get(urlStr, PhoneBean.class, new VolleyUtils.OnResponse<PhoneBean>() {
                    @Override
                    public void OnMap(Map<String, String> map) {
                        map.put("phone", "18856907654");
                        map.put("key", "5778e9d9cf089fc3b093b162036fc0e1");
                    }

                    @Override
                    public void onSuccess(PhoneBean response) {
                        Log.e("TAG", "response---->" + response);
                        textView.setText("get  :" + response.getResultcode() + " " + response.getResult().getCity());
                    }

                    @Override
                    public void onError(String error) {
                        Log.e("TAG", "error---->" + error);
                        textView.setText("error--->" + error);
                    }
                });
    }

    public void btnPost(View view) {
        VolleyUtils.create(this)
                .post(urlStr, PhoneBean.class, new VolleyUtils.OnResponse<PhoneBean>() {
                    @Override
                    public void OnMap(Map<String, String> map) {
                        map.put("phone", "18856907654");
                        map.put("key", "5778e9d9cf089fc3b093b162036fc0e1");
                    }

                    @Override
                    public void onSuccess(PhoneBean response) {
                        Log.e("TAG", "response---->" + response);
                        textView.setText("post  :" + response.getResultcode() + " " + response.getResult().getCity());
                    }

                    @Override
                    public void onError(String error) {
                        Log.e("TAG", "error---->" + error);
                        textView.setText("error--->" + error);
                    }
                });
    }

    public void btnImg(View view) {
        VolleyUtils.create(this)
                .loadImg(imgUrl, img);

//        VolleyUtils.create(this)
//                .loadImg(imgUrl,img,200,200,R.mipmap.ic_launcher,R.mipmap.ic_launcher);
//
//        VolleyUtils.create(this)
//                .loadImg(imgUrl,img,R.mipmap.ic_launcher,R.mipmap.ic_launcher);
    }

    public static void launch(Context mContext) {
        Intent intent = new Intent(mContext,TwoActivity.class);
        mContext.startActivity(intent);
    }
}

GitHub地址: