Android Volley框架学习笔记


       毕业工作这么久了,一直被公司的代码束缚着,每人负责自己的模块,每天不是修改新需求就是改bug,没事的时候也看看其他模块的代码,不过往往看着看着就不想往下看了,反正想不是自己负责的模块,出了什么bug也和自己没关系,哎,这种想法真是大错特错了,别人铺好的路现成给你学习,都没把握住,也许就应了一句话:没有压力就没有动力。有时候就应该给自己点压力,这样才会让自己成长,让自己学到更多的东西。就拿我自己来说,之前我没事的时候看其他模块的代码时,一般比较喜欢看到有界面的代码模块,对这块比较感兴趣,每次只要碰到网络通信之类的操作就立马跳过,感觉太高深了,完全看不懂,也不是完全看不懂,压根就是一点没去看。现在项目代码打算优化,让调查一下Volley,我去,完全懒得看网络通信的人去调查这个,立马着急起来了,赶紧查找资料啊。

什么是Volley
在这之前,我们在程序中需要和网络通信的时候,大体使用的东西莫过于AsyncTaskLoader,HttpURLConnection,AsyncTask,HTTPClient(Apache)等,在Google I/O 2013上,Volley发布了。Volley是Android平台上的网络通信库,能使网络通信更快,更简单,更健壮。

这是Volley名称的由来: a burst or emission of many things or a large amount at once
1.Volley引入的背景
在以前,我们可能面临如下很多麻烦的问题。
比如以前从网上下载图片的步骤可能是这样的流程:
  1. 在ListAdapter#getView()里开始图像的读取。 
  2. 通过AsyncTask等机制使用HttpURLConnection从服务器去的图片资源 
  3. 在AsyncTask#onPostExecute()里设置相应ImageView的属性。 
而在Volley下,只需要一个函数即可。
再比如,屏幕旋转的时候,有时候会导致再次从网络取得数据。为了避免这种不必要的网络访问,我们可能需要自己写很多针对各种情况的处理,比如cache什么的。

再有,比如ListView的时候,我们滚动过快,可能导致有些网络请求返回的时候,早已经滚过了当时的位置,根本没必要显示在list里了,虽然我们可以通过ViewHolder来保持url等来实现防止两次取得,但是那些已经没有必须要的数据,还是会浪费系统的各种资源。

2. Volley提供的功能
简单来说,它提供了如下的便利功能:
  • JSON,图像等的异步下载; 
  • 网络请求的排序(scheduling) 
  • 网络请求的优先级处理 
  • 缓存 
  • 多级别取消请求 
  • 和Activity和生命周期的联动(Activity结束时同时取消所有网络请求) 

Android访问网络,使用HttpURLConnection还是HttpClient?

     大多数的Android应用程序都会使用HTTP协议来发送和接收网络数据,而Android中主要提供了两种方式来进行HTTP操作,HttpURLConnection和HttpClient。这两种方式都支持HTTPS协议、以流的形式进行上传和下载、配置超时时间、IPv6、以及连接池等功能。

HttpClient
DefaultHttpClient和它的兄弟AndroidHttpClient都是HttpClient具体的实现类,它们都拥有众多的API,而且实现比较稳定,bug数量也很少。

但同时也由于HttpClient的API数量过多,使得我们很难在不破坏兼容性的情况下对它进行升级和扩展,所以目前Android团队在提升和优化HttpClient方面的工作态度并不积极。

HttpURLConnection
HttpURLConnection是一种多用途、轻量极的HTTP客户端,使用它来进行HTTP操作可以适用于大多数的应用程序。虽然HttpURLConnection的API提供的比较简单,但是同时这也使得我们可以更加容易地去使用和扩展它。
不过在Android 2.2版本之前,HttpURLConnection一直存在着一些令人厌烦的bug。比如说对一个可读的InputStream调用close()方法时,就有可能会导致连接池失效了。那么我们通常的解决办法就是直接禁用掉连接池的功能

哪一种才是最好的?
在Android 2.2版本之前,HttpClient拥有较少的bug,因此使用它是最好的选择。

而在Android 2.3版本及以后,HttpURLConnection则是最佳的选择。它的API简单,体积较小,因而非常适用于Android项目。压缩和缓存机制可以有效地减少网络访问的流量,在提升速度和省电方面也起到了较大的作用。对于新的应用程序应该更加偏向于使用HttpURLConnection,因为在以后的工作当中我们也会将更多的时间放在优化HttpURLConnection上面。

Volley加载网络图片

  加载网络图片,Volley提供了三种方式:ImageRequest、ImageLoader和NetworkImageView。

下面简单介绍一下三种方式的用法:

 ImageRequest的用法:

基本上分为三步:
1. 创建一个RequestQueue对象。

RequestQueue mQueue = Volley.newRequestQueue(context);
2. 创建一个 ImageRequest对象。

ImageRequest request=new ImageRequest(StringUtil.preUrl(imageUrl), new Listener<Bitmap>() {

			@Override
			public void onResponse(Bitmap bitmap) {
				imageView.setImageBitmap(bitmap);
			}
		}, 0, 0, Config.RGB_565, new ErrorListener() {

			@Override
			public void onErrorResponse(VolleyError arg0) {
				imageView.setImageResource(R.drawable.ic_empty);
			}
		});
ImageRequest的构造函数接收六个参数,第一个参数就是图片的URL地址,此处做了一些处理,就是在给的url如果不是以http开头的,就添加上http 。第二个参数是图片请求成功的回调,这里我们把返回的Bitmap参数设置到ImageView中。第三第四个参数分别用于指定允许图片最大的宽度和高度,如果指定的网络图片的宽度或高度大于这里的最大值,则会对图片进行压缩,指定成0的话就表示不管图片有多大,都不会进行压缩。第五个参数用于指定图片的颜色属性,Bitmap.Config下的几个常量都可以在这里使用,其中ARGB_8888可以展示最好的颜色属性,每个图片像素占据4个字节的大小,而RGB_565则表示每个图片像素占据2个字节大小。第六个参数是图片请求失败的回调,这里我们当请求失败时在ImageView中显示一张默认图片。

3. 将ImageRequest对象添加到RequestQueue里面。

mQueue.add(imageRequest);

ImageLoader的用法:
分为以下四步:

1. 创建一个RequestQueue对象。

2. 创建一个ImageLoader对象。

ImageLoader imageLoader = new ImageLoader(mQueue, new ImageCache() {
	@Override
	public void putBitmap(String url, Bitmap bitmap) {
	}

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

ImageLoader的构造函数接收两个参数,第一个参数就是RequestQueue对象,第二个参数是一个ImageCache对象。

3. 获取一个ImageListener对象。

ImageListener listener=ImageLoader.getImageListener(imageView, R.drawable.car, R.drawable.ic_empty);
通过调用ImageLoader的getImageListener()方法能够获取到一个ImageListener对象,getImageListener()方法接收三个参数,第一个参数指定用于显示图片的ImageView控件,第二个参数指定加载图片的过程中显示的图片,第三个参数指定加载图片失败的情况下显示的图片。

4. 调用ImageLoader的get()方法加载网络上的图片。

imageLoader.get(StringUtil.preUrl(imageUrl),listener);
get()方法接收两个参数,第一个参数就是图片的URL地址,第二个参数则是刚刚获取到的ImageListener对象。当然,如果你想对图片的大小进行限制,也可以使用get()方法的重载,指定图片允许的最大宽度和高度,如下所示:
imageLoader.get(StringUtil.preUrl(imageUrl),listener,100,100);
到这里已经差不多掌握了ImageLoader的用法,但是刚才介绍的ImageLoader的优点却还没有使用到。为什么呢?因为这里创建的ImageCache对象是一个空的实现,完全没能起到图片缓存的作用。其实写一个ImageCache也非常简单,但是如果想要写一个性能非常好的ImageCache,最好就要借助Android提供的LruCache功能了。

public class LruImageCache implements ImageCache{

	private LruCache<String, Bitmap> lruCache;  
	  
    public LruImageCache() {  
        int maxSize = 10 * 1024 * 1024;  
        lruCache = new LruCache<String, Bitmap>(maxSize) {  
            @Override  
            protected int sizeOf(String key, Bitmap bitmap) {  
                return bitmap.getRowBytes() * bitmap.getHeight();  
            }  
        };  
    }  
  
    @Override  
    public Bitmap getBitmap(String url) {  
        return lruCache.get(url);  
    }  
  
    @Override  
    public void putBitmap(String url, Bitmap bitmap) {  
    	lruCache.put(url, bitmap);  
    }  

}
这里我们将缓存图片的大小设置为10M。接着修改创建ImageLoader实例的代码,第二个参数传入LruImageCache 的实例,如下所示
ImageLoader imageLoader = new ImageLoader(mQueue, new LruImageCache());


NetworkImageView的用法:

NetworkImageView是一个自定义控制,它是继承自ImageView的,具备ImageView控件的所有功能,并且在原生的基础之上加入了加载网络图片的功能。估计我们更趋向去控件的使用了,同时NetworkImageView控件的用法要比前两种方式更加简单,大致可以分为以下五步:
1. 创建一个RequestQueue对象。
2. 创建一个ImageLoader对象。
3. 在布局文件中添加一个NetworkImageView控件。

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content" >

    <com.android.volley.toolbox.NetworkImageView
        android:id="@+id/iv_car"
        android:layout_width="match_parent"
        android:layout_height="40dp"
        android:adjustViewBounds="true"
        android:scaleType="centerCrop" />

</LinearLayout>
4. 在代码中获取该控件的实例。

networkImageView = (NetworkImageView) findViewById(R.id.network_iv_car);
5. 设置要加载的图片地址。

                networkImageView.setDefaultImageResId(R.drawable.ic_empty);  
		networkImageView.setErrorImageResId(R.drawable.ic_empty);  
		networkImageView.setImageUrl(StringUtil.preUrl(imageUrl),  imageLoader); 
调用它的setDefaultImageResId()方法、setErrorImageResId()方法和setImageUrl()方法来分别设置加载中显示的图片,加载失败时显示的图片,以及目标图片的URL地址。其中,setImageUrl()方法接收两个参数,第一个参数用于指定图片的URL地址,第二个参数则是前面创建好的ImageLoader对象。

稍后整理一下会把demo源码奉上。
OK,三种方式均已简单介绍完毕,刚看不行,还得需要自己动手去操作一遍,哪怕按着模板手动敲一遍也是有效果的。下面就来总结一下三种方式各自的优点吧。

       ImageRequest可以加载网络图片,可以对图片进行缓存。但ImageLoader也可以用于加载网络上的图片,并且它的内部也是使用ImageRequest来实现的,不过ImageLoader明显要比ImageRequest更加高效,因为它不仅可以帮我们对图片进行缓存,还可以过滤掉重复的链接,避免重复发送请求。 

      NetworkImageView是一个控件,在加载图片的时候它会自动获取自身的宽高,然后对比网络图片的宽度,再决定是否需要对图片进行压缩。也就是说,压缩过程是在内部完全自动化的,并不需要我们关心,NetworkImageView会始终呈现给我们一张大小刚刚好的网络图片,不会多占用任何一点内存,这也是NetworkImageView最简单好用的一点。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值