在上一篇文章之中,我们分析了StringRequest,并详细介绍了Request对象的生命周期及执行流程;这一章,我们将分析Volley框架中剩下的一个工具类——ImageLoader。
显然的,ImageLoader是Volley框架用以处理远程图片请求的一个工具类。此工具类封装了Volley框架对远程图片的请求、缓存等操作。
既然是Volley框架封装好的类,那么ImageLoader所提供的接口(方法)都应在UI线程之中被调用,同时从网络之中所获取的结果也将会在UI线程之中被响应;而且与Volley框架相比,ImageLoader使用了一个更有效率的方法来使得UI线程来执行对请求结果的响应。
至于Rquest对象,Volley框架也封装了一个ImageRequest类专门处理图像类别的网络请求;在ImageLoader类中,对ImageRequest类还进行了进一步的封装,即BatchedImageRequest类,该类主要增加了一个功能,就是管理所有对此次网络请求敢兴趣的兴趣点。
一、ImageLoader中的相关属性
要学习一个陌生的类,首先是看它所定义的属性,属性表如下:
属性名 | 类型 | 描述 |
mRequestQueue | RequestQueue | RequestQueue对象的引用,用以添加请求到工作队列之中; |
mBatchResponseDelayMs | int | 第一个响应到达之后,到此批响应全部到达之前,等待的毫秒数,默认为100; 即在此毫秒数之中,到达的响应都视为同一批响应。 |
mCache | ImageCache | 图片的一级缓存;ImageCahe为一个接口; |
mInFlightRequests | HashMap | 缓存处于飞行状态之中的请求;避免重复请求; |
mBatchedResponses | HashMap | 同一批次的请求; |
mHandler | Handler | 用于处理批量请求的响应; |
mRunnalbe | Runnable | 用于处理批量请求时回调的方法; |
mInFlightRequests是一个HashMap,主要记录处于飞行状态的Request对象,防止同一url请求重复;关于飞行状态请查看【进阶android】Volley源码分析——Volley的工具【StringRequest】一文。
除了ImageCache接口和BatchedImageRequest类之外,ImageLoader还封装了两个接口:ImageListener和ImageContainer。
ImageListener继承Response.ErrorListener接口;在此基础上它自己又定义了一个onResponse抽象方法;ImageListener接口只服务于ImageLoader类;而Response类中的两个接口却是和Request对象打交道。
ImageContainer类封装所有与图片请求响应相关的数据,主要有四种:成功加载的图片,加载成功(失败)的监听器ImageListener接口,图片请求的缓存key,图片请求的URL;上文提到BatchedImageRequest类的主要功能是管理所有对此次网络请求(Request对象)敢兴趣的兴趣点。而这里的兴趣点这个概念,就是通过ImageContainer类实现。
介绍完主要的属性和响应的内部类、内部接口时,我们便开始分析ImageLoader的工作流程。
二、ImageLoader的工作流程
public ImageContainer get(String requestUrl, ImageListener imageListener,int maxWidth, int maxHeight)
requestUrl:图片的URL;
protected void deliverResponse(Bitmap response) {
mListener.onResponse(response);
}
该方法调用了监听器mListener的方法;在ImageRequest类中mListener的类型为Response.Listener,并且mListener的值是通过ImageRequest的构造函数传递过来的。如此我们便可以根据上文网络请求流程的分析,知道ImageRequest对象是在ImageLoader类中的get方法进行实例的,具体代码如下:
public ImageContainer get(String requestUrl, ImageListener imageListener,
int maxWidth, int maxHeight) {
......
// The request is not already in flight. Send the new request to the network and
// track it.
Request<?> newRequest =
new ImageRequest(requestUrl, new Listener<Bitmap>() {
@Override
public void onResponse(Bitmap response) {
onGetImageSuccess(cacheKey, response);//成功获取图片之后,回调的方法
}
}, maxWidth, maxHeight,
Config.RGB_565, new ErrorListener() {
@Override
public void onErrorResponse(VolleyError error) {
onGetImageError(cacheKey, error);//获取图片失败后,回调的方法
}
});
......
}
通过代码可以看出,ImageRequest通过一个匿名类执行了Response.Listener接口;这个匿名类中的onResponse方法直接调用了ImageLoader的onGetImageSuccess方法。
由图可以看出,网络响应处理的总体流程并不复杂;其需要注意的是第三步:批量处理请求的响应,具体执行这一步的是ImageLoader的 batchResponse方法。
private void batchResponse(String cacheKey, BatchedImageRequest request) {
mBatchedResponses.put(cacheKey, request);//将本次Request请求添加到批量请求集合之中
// If we don't already have a batch delivery runnable in flight, make a new one.
// Note that this will be used to deliver responses to all callers in mBatchedResponses.
//如果我们还没有一个用来处理批量请求的回调方法,创建一个。
//注意此回调方法将用来处理响应请求中每一个请求。
if (mRunnable == null) {
mRunnable = new Runnable() {
@Override
public void run() {
for (BatchedImageRequest bir : mBatchedResponses.values()) {
for (ImageContainer container : bir.mContainers) {//处理一个请求所有的兴趣点
// If one of the callers in the batched request canceled the request
// after the response was received but before it was delivered,
// skip them.
if (container.mListener == null) {
continue;
}
if (bir.getError() == null) {
container.mBitmap = bir.mResponseBitmap;
container.mListener.onResponse(container, false);//回调兴趣点的方法!
}......
}
}
mBatchedResponses.clear();//同批次的请求皆被处理,清空
mRunnable = null;//开始一场新的批量处理任务
}
};
// Post the runnable.
//创建消息后mBatchResponseDelayMs毫秒后,再执行消息
//mBatchResponseDelay时间内,添加到mBatchedResponses之中的所有Request对象,视为同批次的请求。
mHandler.postDelayed(mRunnable, mBatchResponseDelayMs);
}
}
batchResponse通过向UI现场发送一个定时消息,来实现批量处理一批请求;这种方式与BufferedInputStream有点类似,将物理源(例如文件)中的内容读入一个缓冲区,当缓冲区满了,或者调用了flush方法,则将缓冲区直接返回给调用者。在batchResponse方法之中,mBatchResponseDelay就类似于一个缓冲区,当时间未到时(BufferedInputStream是空间未满时),将接收到的请求添加到缓冲区,时间一到就一次性处理缓冲区中所有的Request对象。
三 总结
至此,关于Volley框架的五篇分析文章就至此结束。当然由于本人自身水平所限,文章肯定有一些不对的地方,希望大家指出!
愿大家一起进步,谢谢!