Android组件Volley学习

1. 项目地址 本地下载

2. 参考博文

http://arnab.ch/blog/2013/08/asynchronous-http-requests-in-android-using-volley/

http://blog.csdn.net/guolin_blog/article/details/17482095

Volley是Google提供的网络通信库,通过它可以使得从网络获取数据更加的方便。它对网络的请求做了很多封装优化,让开发者更加便捷的开发。在新的Android文档中,已经加入了Volley方面的部分,在Training部分。网上有很多对它的参考,当然,Android文档就是一份很好的参考。大牛都批评只会使用而不去研究它源码的码农,但,我还是先浅尝辄止,不去学习的它的源码。不过,他们都推荐它的源码写得非常好,那当然要适时的找时间学习它的源码。下面记录下它的使用方法,涉及到的有异步请求文本,json,图片等请求,Volley是对返回的字节流做了封装。当然,我们也可以根据需要继承Request,定制自己的Request。另外,需要记录的是内存级别和硬盘(sd卡)的缓存处理。

我们首先要获得一个RequestQueue对象,文档推荐使用单例模式。推荐的方法是实现一个单模式类,提供一个获取对象的单例方法。如下:

    public RequestQueue getRequestQueue() {
        if (mRequestQueue == null) {
            // getApplicationContext() is key, it keeps you from leaking the
            // Activity or BroadcastReceiver if someone passes one in.
            mRequestQueue = Volley.newRequestQueue(mCtx.getApplicationContext());
        }
        return mRequestQueue;
    }

其中, Volley#newRequestQueue(Context context) 这个静态方法的参数很讲究。不推荐使用Activity的context,而是使用Application的context,正如上面的代码所示。这样,即使一个Activity销毁了,RequestQueue对象也不会跟随它销毁,而是和这个APP的生命周期相关联,避免了重复的生成。

接着,我们来看请求文本数据,如下:

StringRequest stringRequest = new StringRequest(Request.Method.GET, url,
            new Response.Listener() {
    @Override
    public void onResponse(String response) {
        // Display the first 500 characters of the response string.
        mTextView.setText("Response is: "+ response.substring(0,500));
    }
}, new Response.ErrorListener() {
    @Override
    public void onErrorResponse(VolleyError error) {
        mTextView.setText("That didn't work!");
    }
});

StringRequest有多个重载的构造方法,可以使用GET方式和POST方式,相应的有请求成功和请求失败的回调监听函数。那么对于POST方式,如何传递参数呢?在JsonObjectRequest的构造方法中,有个参数选项可以传进一个Map结构的键值对参数。而StringRequest 中确没有,参考博文的方法是,重写StringRequest的getParams()方法,如下:

StringRequest stringRequest = new StringRequest(Method.POST, url,  listener, errorListener) {
	@Override
	protected Map<String, String> getParams() throws AuthFailureError {
		Map<String, String> map = new HashMap<String, String>();
		map.put("params1", "value1");
		map.put("params2", "value2");
		return map;
	}
};

有了请求对象后,就把该对象加入的请求队列RequestQueue中即可。

// Add the request to the RequestQueue.
queue.add(stringRequest);


如何请求JSON数据呢?就是构造一个JsonObjectRequest或者JsonArrayRequest请求对象,形式和上面大同小异。然后加入到请求队列中即可。

那如何,请求图片资源呢?记录这两种好用的方式。一种是构造一个ImageRequest对象,然后在请求成功的回调函数中ImageView#setImageBitmap 即可。构造方法中可以指定图片的大小。

		ImageRequest imageRequest = new ImageRequest(imgUrl1, new Listener<Bitmap>() {

			@Override
			public void onResponse(Bitmap response) {
				mImageView1.setImageBitmap(response);
			}
		}, 200, 200, Config.ARGB_8888, new ErrorListener() {

			@Override
			public void onErrorResponse(VolleyError error) {
				Log.e(TAG, "imageRequest-->"+error.getMessage());
			}
		});
		
		mQueue.add(imageRequest);

和上面的类似。另一种功能强大一些,它可以设定加载中的图片,加载失败的图片,和内存缓存的策略。该方法使用的是ImageLoader类实现,首先生成一个该对象:

	mImageLoader = new ImageLoader(mQueue, new LruBitmapCache(this));

第一个参数是请求队列,第二个参数是缓存策略。文档中提供一个例子。当然,我们可以自己实现或者实现为不使用缓存。最后,我们调用一下#get方法就可以了,

mImageLoader.get(imgUrl2, ImageLoader.getImageListener(mImageView2, android.R.drawable.alert_dark_frame, android.R.drawable.edit_text));

内存缓存中,有个奇怪的事,我在文档提供的 LruBitmapCache类的 #getBitmap 方法中,加入log观察,发现多次请求同一个url图片时,它的 #get 方法返回的对象返回为null,根本就没有缓存到内存中。


基本的网络请求,就如上。有时,我们需要设置一下HTTP头,该如何做?覆盖请求对象的 #getHeaders 方法即可,

       @Override
       public Map<String, String> getHeaders() throws AuthFailureError {
           HashMap<String, String> headers = new HashMap<String, String>();
           headers.put("CUSTOM_HEADER", "Yahoo");
           headers.put("ANOTHER_CUSTOM_HEADER", "Google");
           return headers;
       }

有时,当我们退出Activity时,希望取消正在进行的网络操作,我们可以调用RequestQueue的一系列的 #cancel* 方法,比如,

public static final String TAG = "MyTag";
StringRequest stringRequest; // Assume this exists.
RequestQueue mRequestQueue;  // Assume this exists.

// Set the tag on the request.
stringRequest.setTag(TAG);

// Add the request to the RequestQueue.
mRequestQueue.add(stringRequest);

@Override
protected void onStop () {
    super.onStop();
    if (mRequestQueue != null) {
        mRequestQueue.cancelAll(TAG);
    }
}

有时,我们需要根据自己的需求封装请求返回的格式,那么我们可以继承Request来实现一个,文档中给出一个Gson的例子,是很好的参考,

public class GsonRequest<T> extends Request<T> {
    private final Gson gson = new Gson();
    private final Class<T> clazz;
    private final Map<String, String> headers;
    private final Listener<T> 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
     * @param headers Map of request headers
     */
    public GsonRequest(String url, Class<T> clazz, Map<String, String> headers,
            Listener<T> listener, ErrorListener errorListener) {
        super(Method.GET, url, errorListener);
        this.clazz = clazz;
        this.headers = headers;
        this.listener = listener;
    }

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

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

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

现在,还有一个较重要的问题要记录,就是缓存问题。Volley默认是对每一个url 都缓存到sd卡中(实验得出)。默认大小是5M。那么我们如何取消缓存或者修改缓存大小呢?修改缓存大小,可以如下(参考文档),

RequestQueue mRequestQueue;

// Instantiate the cache
Cache cache = new DiskBasedCache(getCacheDir(), 1024 * 1024); // 1MB cap

// Set up the network to use HttpURLConnection as the HTTP client.
Network network = new BasicNetwork(new HurlStack());

// Instantiate the RequestQueue with the cache and network.
mRequestQueue = new RequestQueue(cache, network);

// Start the queue
mRequestQueue.start();

String url ="http://www.myurl.com";

// Formulate the request and handle the response.
StringRequest stringRequest = new StringRequest(Request.Method.GET, url,
        new Response.Listener<String>() {
    @Override
    public void onResponse(String response) {
        // Do something with the response
    }
},
    new Response.ErrorListener() {
        @Override
        public void onErrorResponse(VolleyError error) {
            // Handle error
    }
});

// Add the request to the RequestQueue.
mRequestQueue.add(stringRequest);
...

那么,如何设置不进行缓存呢,暂时没有发现直接的方法,但阅读源码,可以很快的实现,方法如下,

	/**
	 * 没有硬盘缓存
	 * @param context
	 * @param stack
	 * @return
	 */
    public static RequestQueue newRequestQueue(Context context, HttpStack stack) {

    	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 = new RequestQueue(new NoCache(), network);
        queue.start();

        return queue;
    }

和原来代码中不同的是,删除了一些缓存初始化的代码,以及构造RequestQueue请求队列时,传入的是 NoCache对象,这样即可。我们也可以通过RequestQueue#getCache方法获得Cache对象,然后进行移除指定key的缓存文件,或者clear 清空全部。这样,功能就达到了 组件Android-Universal-Image-Loader所能实现的。



  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值