开源框架Volley的使用

时间:2022-11-23 19:47:59

一、简介

Volley是Google在2003年的I/O大会上推出的通信框架,结合了AsyncHttpClient和Universal-Image-Loader的优点,简化了http的使用和异步加载图片的使用步骤。Android中的Http实现主要有HttpUrlConnection和HttpClient两种,关于二者的选择Google在Blog中表示推荐在姜饼小人(API level = 9)及以上的版本中使用Java的HttpUrlConnection,而在之前的版本使用Apache的HttpClient,这在Volley这个框架中也有明确的体现。
获取Volley的方式: https://android.googlesource.com/platform/frameworks/volley
我们可以直接下载jar包,拷贝到libs中。

二、使用场景

1.数据量小、请求频繁。
备注:不适用于文件的上传和下载。

三、使用示例

1、简单的请求
Http的通信最主要的部分应该就是发出请求和接收响应了,所以Volley的比较核心的一个类就是RequestQueue,一个请求队列。它负责管理工作线程,读写缓存,和解析、分发响应(具体操作还是由具体的类实现),即将发出的Http请求都会首先聚集在这里等待工作线程来实现请求。Volley进行Http通信的简单步骤:
①获取RequestQueue
②实例化一个Request
③将Request加入RequestQueue,等待工作线程执行。

Request的几个子类:
①public StringRequest(int method, String url, Listener listener,ErrorListener errorListener);
参数说明:从左到右分别是请求方法(都封装在Request中的Method接口内),请求URL,响应监听接口实例,错误监听接口实例。执行该方法,在响应后获得的返回数据是一个字符串。

②public JsonObjectRequest(int method, String url, JSONObject jsonRequest,Listener listener, ErrorListener errorListener);
public JsonObjectRequest(String url, JSONObject jsonRequest, Listener listener,ErrorListener errorListener);
参数说明:如果是GET请求的话,jsonRequest传入null就可以了,否则在未指明请求方法的情况下(也就是第二个构造函数)会默认为POST请求。执行该方法,在响应后获得的返回数据是一个JSONObject对象。

③public JsonArrayRequest(String url, Listener listener, ErrorListener errorListener);
执行该方法,在响应后获得的返回数据是一个JSONArray数组。

④public ImageRequest(String url, Response.Listener listener, int maxWidth, int maxHeight,Config decodeConfig, Response.ErrorListener errorListener);
执行该方法,在响应后获得的返回数据是一个Bitmapt图片,可以很方便的设置给ImageView控件。

下面给出几个请求的示例
①GET方式

private void stringRequest(String url) {
        final ProgressDialog progressDialog = ProgressDialog.show(this,"Title", "Loading...");
        RequestQueue queue = Volley.newRequestQueue(this);
        // 根据给定的URL新建一个请求
        StringRequest stringRequest = new StringRequest(Request.Method.GET,
                url, new Response.Listener() {
                    @Override
                    public void onResponse(Object response) {
                        if (progressDialog.isShowing()&& progressDialog != null) {
                            progressDialog.dismiss();
                        }
                    }
                }, new Response.ErrorListener() {
                    @Override
                    public void onErrorResponse(VolleyError error) {
                        if (progressDialog.isShowing()&& progressDialog != null) {
                            progressDialog.dismiss();
                        }
                    }
                });
        queue.add(stringRequest);
    }

②POST方式,普通方式提交参数。

private void postRequestWithParams(String url) {
        RequestQueue requestQueue = Volley.newRequestQueue(this);
        StringRequest stringRequest = new StringRequest(Request.Method.POST,
                url, new Response.Listener<String>() {
                    @Override
                    public void onResponse(String response) {
                    }
                }, new Response.ErrorListener() {
                    @Override
                    public void onErrorResponse(VolleyError error) {
                    }
                }) {
            @Override
            protected Map<String, String> getParams() {
                // 在这里设置需要post的参数
                Map<String, String> map = new HashMap<String, String>();
                map.put("name", "value1");
                map.put("password", "value2");
                return map;
            }
        };
        requestQueue.add(stringRequest);
    }

③POST方式,提交的参数为JSONObject类型。但这个看服务器是否要支持这种请求方式,比如常见的spring mvc服务端,就很难支持json的请求方式。

private void postRequestWithJSON(String url) {
        RequestQueue requestQueue = Volley.newRequestQueue(this);

        Map<String, String> params = new HashMap<String, String>();
        params.put("name", "value1");
        params.put("password", "value2");
        JSONObject jsonObject = new JSONObject(params);

        JsonRequest<JSONObject> jsonRequest = new JsonObjectRequest(
                Method.POST, url, jsonObject,
                new Response.Listener<JSONObject>() {
                    @Override
                    public void onResponse(JSONObject response) {
                        //
                    }
                }, new Response.ErrorListener() {
                    @Override
                    public void onErrorResponse(VolleyError error) {
                        //
                    }
                }) {

            @Override
            public Map<String, String> getHeaders() {
                HashMap<String, String> headers = new HashMap<String, String>();
                headers.put("Accept", "application/json");
                headers.put("Content-Type", "application/json; charset=UTF-8");

                return headers;
            }
        };
        requestQueue.add(jsonRequest);
    }

④POST请求,继承Request类,自定义Request的请求参数列表。
NormalPostRequest类

package com.example.volleydemo;

import java.io.UnsupportedEncodingException;
import java.util.Map;

import org.json.JSONException;
import org.json.JSONObject;

import com.android.volley.AuthFailureError;
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;

public class NormalPostRequest extends Request<JSONObject> {
    private Map<String, String> mMap;
    private Listener<JSONObject> mListener;

    public NormalPostRequest(String url, Listener<JSONObject> listener,
            ErrorListener errorListener, Map<String, String> map) {
        super(Request.Method.POST, url, errorListener);

        mListener = listener;
        mMap = map;
    }

    // mMap是已经按照前面的方式,设置了参数的实例
    @Override
    protected Map<String, String> getParams() throws AuthFailureError {
        return mMap;
    }

    // 此处因为response返回值需要json数据,和JsonObjectRequest类一样即可
    @Override
    protected Response<JSONObject> parseNetworkResponse(NetworkResponse response) {
        try {
            String jsonString = new String(response.data,HttpHeaderParser.parseCharset(response.headers));

            return Response.success(new JSONObject(jsonString),HttpHeaderParser.parseCacheHeaders(response));
        } catch (UnsupportedEncodingException e) {
            return Response.error(new ParseError(e));
        } catch (JSONException je) {
            return Response.error(new ParseError(je));
        }
    }

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

调用自定义的类,进行POST请求

//可以自定义传入的参数
    private void postRequestWithCustom(String url,Map<String,String> params){
        RequestQueue requestQueue = Volley.newRequestQueue(getApplicationContext());
        Request<JSONObject> request = new NormalPostRequest(url,
            new Response.Listener<JSONObject>() {
                @Override
                public void onResponse(JSONObject response) {
                    //
                }
            }, new Response.ErrorListener() {
                @Override
                public void onErrorResponse(VolleyError error) {
                    //
                }
            }, params);
        requestQueue.add(request);
    }

2.请求图片
Volley提供了多种请求图片的方式
①ImageRequest能够处理单张图片,返回bitmap。

private void requestImage(final ImageView imageView){
        RequestQueue requestQueue = Volley.newRequestQueue(this);
        ImageRequest imgRequest=new ImageRequest(url, new Response.Listener<Bitmap>() {  
            @Override  
            public void onResponse(Bitmap arg0) {  
                imageView.setImageBitmap(arg0);  
            }  
        }, 300, 200, Config.ARGB_8888, new ErrorListener(){  
            @Override  
            public void onErrorResponse(VolleyError arg0) {  
                //
            }             
        });  
        requestQueue.add(imgRequest);  
    }

②使用ImageLoader。
实例化一个ImageLoader需要一个RequestQueue,还有一个ImageCache,这是一个ImageLoader内部定义的接口,用来实现L1缓存——内存缓存(Volley在RequestQueue中已经实现了L2缓存——文件缓存)。ImageLoader中并没有对传入的ImageCache在使用前判空的代码,传null进去会出错的。如果实在不想弄内存缓存,实现一个什么都不做的ImageCache就好了。

private void requestImageWithImageLoader(String url,ImageView iv,int default_image, int error_image){
        RequestQueue queue = Volley.newRequestQueue(this);
        ImageLoader loader = new ImageLoader(queue, new ImageCache() {
            @Override
            public void putBitmap(String url, Bitmap bitmap) {      
            }

            @Override
            public Bitmap getBitmap(String url) {
                return null;
            }
        });
         //default_image是正在加载图片时占位用的
         //error_image是加载不成功时显示的图片
        loader.get(url, ImageLoader.getImageListener(iv,default_image, error_image));
    }

③使用NetworkImageView请求并显示图片
NetworkImageView继承自ImageView。

private void requestImageWithNetworkImageView(String url,NetworkImageView networkImageView,int defult_image,int error_image){
        //networkImageView = (NetworkImageView) findViewById(R.id.network_image_view); 

        RequestQueue requestQueue = Volley.newRequestQueue(getApplicationContext());
        networkImageView.setDefaultImageResId(defult_image);  
        networkImageView.setErrorImageResId(error_image);
        networkImageView.setImageUrl(url, new ImageLoader(queue, new ImageCache() {

            @Override
            public void putBitmap(String url, Bitmap bitmap) {

            }

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

3.取消请求
Activity里面启动了网络请求,而在这个网络请求还没返回结果的时候,Activity被结束了,此时如果继续使用其中的Context等,除了无辜的浪费CPU,电池,网络等资源,有可能还会导致程序crash,所以,我们需要处理这种一场情况。使用Volley的话,我们可以在Activity停止的时候,同时取消所有或部分未完成的网络请求。Volley里所有的请求结果会返回给主进程,如果在主进程里取消了某些请求,则这些请求将不会被返回给主线程。Volley支持多种request取消方式。
①取消指定的request

@Override  
   public void onStop() {  
       for (Request request : queue) {  
           if(...){
           request .cancel();  
           }
       }  
   } 

②取消队列中的所有请求

@Override  
protected void onStop() {   
    super.onStop();  
    queue.cancelAll(this);  
}  

③可以根据RequestFilter或者Tag来终止某些请求

@Override  
rotected void onStop() {  
    super.onStop();  
    queue.cancelAll( new RequestFilter() {});  
    //queue.cancelAll(new Object()); 

四、自定义缓存类

1.自定义的一个图片缓存类

package com.example.volleydemo;


import android.graphics.Bitmap;
import android.support.v4.util.LruCache;

import com.android.volley.toolbox.ImageLoader.ImageCache;

public class LruImageCache implements ImageCache{

    private static LruCache<String, Bitmap> mMemoryCache;

    private static LruImageCache lruImageCache;

    private LruImageCache(){
        // Get the Max available memory,set cacheSize 1/8
        int maxMemory = (int) Runtime.getRuntime().maxMemory();
        int cacheSize = maxMemory / 8;
        //cacheSize:缓存区大小,也可以设置为固定值10*1024*1024=10MB
        mMemoryCache = new LruCache<String, Bitmap>(cacheSize){
            @Override
            protected int sizeOf(String key, Bitmap bitmap){
                return bitmap.getRowBytes() * bitmap.getHeight();
            }
        };      
    }

    public static LruImageCache instance(){
        if(lruImageCache == null){
            lruImageCache = new LruImageCache();
        }
        return lruImageCache;
    }

    @Override
    public Bitmap getBitmap(String arg0) {      
        return mMemoryCache.get(arg0);  
    }

    @Override
    public void putBitmap(String arg0, Bitmap arg1) {
        if(getBitmap(arg0) == null){
            mMemoryCache.put(arg0, arg1);
        }       
    }

}

未完待续…