Android Volley 研究综述(二)

文章目录
  1. 1. ImageRequest 的使用
  2. 2. ImageLoader 的使用
  3. 3. NetworkImageView 的使用
  4. 4. 参考文献

Nothing is given, everything is earned, you work for what you have.

Universal-Image-Loader 具备强大的网络图片加载功能,使用 Volley,可以实现类似的效果,并且,在性能上也毫不逊色。本篇在 Android Volley 研究综述(一) 的基础上继续展开,分析关于 Volley 加载网络图片。

ImageRequest 的使用

ImageRequestDemo 地址: ImageRequestDemo

ImageRequest,指定一个 URL,并在响应回调中接收一张图片。具体来说,ImageRequest 是一个封装好的 request,用来在给定的 URL 中获得一张图片,同时调回一张解码过的位图。它也提供了些便捷的特性,如指定一种大小来重新裁剪。其主要优点是,Volley 的线程调度确保昂贵的图片操作(解码,重新裁剪)自动地在工作线程中发生。

以上来自官网,总结来说,同 StringRequest 和 JsonRequest 类似,使用大体分以下三步:

I.创建一个 RequestQueue 对象。

II.创建一个 Request 对象。

III.将 Request 对象添加到 RequestQueue 里面。

同样,首先,在 MainActivity 的 onCreate() 方法里,需要获取到一个 RequestQueue 对象:

1
RequestQueue queue = Volley.newRequestQueue(this);

接着,初始化:

1
2
final ImageView mImageView;
mImageView = (ImageView) findViewById(R.id.myImage);

同时,在 drawable 目录下放入一张 default_image 图片,删掉 activity_main.xml 中的 TextView,即删掉:

1
2
3
4
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Hello World!"/>

添加 ImageView:

1
2
3
4
5
6
7
<ImageView
android:id="@+id/myImage"
android:layout_width="200dp"
android:layout_height="200dp"
android:layout_marginLeft="65dp"
android:layout_marginTop="150dp"
android:layout_gravity="center"/>

然后,要 new 出一个 ImageRequest 对象:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
String url = "https://i.loli.net/2019/03/03/5c7b86dd8a1ea.jpg";

ImageRequest imageRequest = new ImageRequest(url,
new Response.Listener<Bitmap>() {

@Override
public void onResponse(Bitmap response) {
mImageView.setImageBitmap(response);
}
}, 0, 0, Bitmap.Config.RGB_565, new Response.ErrorListener() {

@Override
public void onErrorResponse(VolleyError error) {
mImageView.setImageResource(R.drawable.default_image);
}
});

ImageRequest() 方法接收六个参数,第一个是图片的 URL 地址;第二个是图片请求成功的回调,将返回的 Bitmap 参数设置到 ImageView 中;第三个和第四个分别用于指定图片的最大宽度和最大高度,若指定图片的宽度或高度大于最大值,则对图片进行压缩,指定为 0,则无论图片多大,都不会压缩;第五个用于指定图片的颜色属性;第六个是图片请求失败的回调,失败时在 ImageView 中显示一张默认的图片,即显示 default_image。

最后,将该 ImageRequest 对象添加到 RequestQueue 里面即可:

1
queue.add(imageRequest);

同样,不要忘了在 AndroidManifest.xml 文件中添加一条权限:

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

运行程序,发送网络请求,正常成功的话,显示:

如果因各种意外原因,请求失败的话,显示:

ImageLoader 的使用

ImageLoaderDemo 地址: ImageLoaderDemo

ImageLoader,一个处理加载与缓存从远程 URLs 获取图片的帮助类。它是一个大量 ImageRequest 的协调器,如将许多小图片放入 ListView 中。ImageLoader 提供了一个超前于标准 Volley 缓存的内存内缓存,这对于防止抖动是重要的。在未堵塞或延迟主线程的情况下,这让实现缓存击中成为可能,不过,当使用磁盘 I/O 时是不可能的。ImageLoader 也能实现响应合并,没有它的话,几乎每一个响应处理机会将 bitmap 放到 view 上,并且会造成每一张图片的布局传递。合并让同时传送多个响应成为可能,这提升了性能。

以上来自官网,总结来说,ImageLoader 也可以用来加载网络上的图片,并且它的内部也是使用 ImageRequest 实现的。但是,ImageLoader 较 ImageRequest 更高效,它不仅可以对图片进行缓存,还可以过滤掉重复的链接,避免重复发送请求。
ImageLoader 不是继承自 Request,用法也与之前有所不同,大致分四步:

I.创建一个 RequestQueue 对象。

II.创建一个 ImageLoader 对象。

III.获取一个 ImageListener 对象。

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

具体如下:

第一步与初始化部分同上述 ImageRequest 的一样。

接着,new 一个 ImageLoader 对象:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
String url = "https://i.loli.net/2019/03/03/5c7b86dd8a1ea.jpg";

ImageLoader imageLoader = new ImageLoader(queue, new ImageLoader.ImageCache() {

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

}

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

ImageLoader() 方法接收两个参数,第一个是 RequestQueue 对象,第二个是 ImageCache 对象,暂且先 new 出一个空的 ImageCache 实现。

然后,获取一个 ImageListener 对象,在此之前的基础上,再放一张 failed_image 图片至 drawable 目录下:

1
2
ImageLoader.ImageListener listener = ImageLoader.getImageListener(mImageView,
R.drawable.default_image, R.drawable.failed_image);

调用 ImageLoader 的 getImageListener() 方法获取到一个 ImageListener 对象,getImageListener() 方法接收三个参数,第一个指定显示图片的 ImageView 控件,第二个指定加载图片过程中默认显示的图片,第三个指定加载图片失败时显示的图片。

最后,调用 ImageLoader 的 get() 方法加载图片:

1
imageLoader.get(url, listener);

get() 方法接收两个参数,第一个是图片的 URL, 第二个是获取到的 ImageListener 对象。另外,要对图片的大小进行限制,使用 get() 方法的重载,指定图片允许的最大宽度和最大高度,如下:

1
imageLoader.get(url, listener, 200, 200);

同样,不要忘了在 AndroidManifest.xml 文件中添加同上面一样的权限。

运行程序,先会显示默认的图片,最后效果图如下:

ImageLoaderCacheDemo 地址: ImageLoaderCacheDemo

学会了 ImageLoader 的使用,但是其优点却没有用到。上述代码中,创建的 ImageCache 对象是一个空实现,没能起到图片缓存的作用。这里,借助 Android 提供的 LruCache 功能,写一个性能很好的 ImageCache,新建一个 BitmapCache 并实现 ImageCache 接口:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
public class BitmapCache implements ImageLoader.ImageCache {

private LruCache<String, Bitmap> mCache;

public BitmapCache() {
int maxSize = 1 * 1024 * 1024;
mCache = 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 mCache.get(url);
}

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

将缓存图片的大小设置为 1M,修改创建 ImageLoader 实例的代码,第二个参数传入 BitmapCache 的实例:

1
ImageLoader imageLoader = new ImageLoader(queue, new BitmapCache());

然后其他所有,与前面的设置及代码一样,运行,Logcat 报出 unknown buffer。在 Stack Overflow 上找到解决办法,即于 AndroidManifest.xml 文件中添加最后一行代码,具体如图:

1
2
3
4
5
6
7
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:supportsRtl="true"
android:theme="@style/AppTheme"
android:largeHeap="true">

使用 largeHeap,请求系统为 Dalvik 虚拟机分配更大的内存空间,解决内存过小不够用导致的 OutOfMemoryError 的问题。最后,再运行,显示与上面的图片显示一样。

NetworkImageView 的使用

NetworkImageViewDemo 地址: NetworkImageViewDemo

NetworkImageView,建立在 ImageLoader 上,并且在你的图片通过网络 URL 取回的情况下,有效地替代 ImageView。如果 view 从层级结构中分离,NetworkImageView 也能管理取消待处理的请求。

以上来自官网,总结来说,NetworkImageView 是一个自定义控制,继承自 ImageView,具备 ImageView 的所有功能,并在原始的基础上拥有加载网络图片的功能。大致分以下五步:

I.创建一个 RequestQueue 对象。

II.创建一个 ImageLoader 对象。

III.布局文件中添加一个 NetworkImageView 的控件。

IV.代码中获取该控件的实例。

V.设置要加载的图片地址。

第一步与初始化部分仍然同 ImageRequest 的大致一样。不过,添加 ImageView 部分改为添加 NetworkImageView 部分如下:

1
2
3
4
5
6
7
<com.android.volley.toolbox.NetworkImageView
android:id="@+id/networkImageView"
android:layout_width="200dp"
android:layout_height="200dp"
android:layout_marginLeft="65dp"
android:layout_marginTop="150dp"
android:layout_gravity="center"/>

然后,得到了 NetworkImageView 控件的实例后,调用 setDefaultImageResId() 方法、setErrorImageResId() 方法和 setImageUrl() 方法来分别设置加载成功显示的图片,加载失败时显示的图片和目标图片的 URL 地址。如下:

1
2
3
mNetworkImageView.setDefaultImageResId(R.drawable.default_image);
mNetworkImageView.setErrorImageResId(R.drawable.failed_image);
mNetworkImageView.setImageUrl(url, imageLoader);

setImageUrl() 方法接收两个参数,第一个指定图片的 URL 地址,第二个是前面创建好的 ImageLoader 对象,姑且使用未设置图片缓存的代码。然后一些基本事项无需赘述,运行程序,看到效果与 ImageLoader 的效果是一样的。

值得注意的是,使用 ImageRequest 和 ImageLoader 两种方式加载图片都可以传入一个最大宽度和最大高度的参数来对图片进行压缩。然而,对于 NetworkImageView,并不需要提供任何设置最大宽高的方法也能对加载的图片进行压缩。它是一个控件,在加载图片的时候会自动获取自身的宽高,然后对比网络图片的宽高,再决定是否需要对图片进行压缩。整个压缩过程在内部是完全自动化的,其呈现给我们的始终是一张大小刚好的图片,不会多占用任何一点内存。

当然,不愿压缩图片的话,只需要在布局文件中将 layout_width 和 layout_height 都设置成 wrap_content 即可。至此,关于 Android Volley 研究综述(二)到此结束,(三)未完待续。

本人才疏学浅,如有疏漏错误之处,望读者中有识之士不吝赐教,谢谢。

1
Email: [email protected] / WeChat: Wolverine623

您也可以关注我个人的微信公众号码农六哥第一时间获得博客的更新通知,或后台留言与我交流

参考文献

1.http://developer.android.com/training/volley/request.html

2.http://developer.android.com/training/volley/requestqueue.html

3.http://blog.csdn.net/guolin_blog/article/details/17482165