displayImage方法进行图片的加载,下面我们着重看一下这个方法的实现,其中包括LoadAndDisplayImageTask作为图片硬盘加载与网络加载的任务,ProcessAndDisplayImageTask作为缓存中加载图片的任务,具体过程见注释。
public void displayImage(String uri, ImageAware imageAware, DisplayImageOptions options,
ImageSize targetSize, ImageLoadingListener listener, ImageLoadingProgressListener progressListener) {
//************以下内容检查参数是否为空*******************
checkConfiguration();
if (imageAware == null) {
throw new IllegalArgumentException(ERROR_WRONG_ARGUMENTS);
}
if (listener == null) {
listener = defaultListener;
}
if (options == null) {
options = configuration.defaultDisplayImageOptions;
}
//如果Uri为空
if (TextUtils.isEmpty(uri)) {
engine.cancelDisplayTaskFor(imageAware);
listener.onLoadingStarted(uri, imageAware.getWrappedView());
//如果设置了Uri为空的默认图片
if (options.shouldShowImageForEmptyUri()) {
//设置空Uri默认图
imageAware.setImageDrawable(options.getImageForEmptyUri(configuration.resources));
} else {
//设置为空
imageAware.setImageDrawable(null);
}
//回调加载成功
listener.onLoadingComplete(uri, imageAware.getWrappedView(), null);
return;
}
if (targetSize == null) {
//获取容器(ImageView)的长宽
targetSize = ImageSizeUtils.defineTargetSizeForView(imageAware, configuration.getMaxImageSize());
}
//*****************生成内存中使用的键 并与 ImageView及其相关图片显示数据(imageAware)绑定********
//使用uri和大小生成 内存中的键
String memoryCacheKey = MemoryCacheUtils.generateKey(uri, targetSize);
//在ImageLoadEngine中 建立imageAware(图片信息,包括ImageView及其所对应的图片) 和 键(内存索引键) 的关系
//ImageLoadEngine (姑且称作下载引擎) 中维护
// 1.下载用到的线程
// 2.imageAware 和 键 的关系
engine.prepareDisplayTaskFor(imageAware, memoryCacheKey);
//**********************开始加载********************
//监听开始下载
listener.onLoadingStarted(uri, imageAware.getWrappedView());
//尝试用上面生成的键在内存中获取Bitmap
Bitmap bmp = configuration.memoryCache.get(memoryCacheKey);
if (bmp != null && !bmp.isRecycled()) {
L.d(LOG_LOAD_IMAGE_FROM_MEMORY_CACHE, memoryCacheKey);
//在内存中成功取出图片
if (options.shouldPostProcess()) {
//如果options中设置了postProcessor,即显示图片前需要对图片进行一定的处理
//生成图片加载信息
ImageLoadingInfo imageLoadingInfo = new ImageLoadingInfo(uri, imageAware, targetSize, memoryCacheKey,
options, listener, progressListener, engine.getLockForUri(uri));
//调用options中设置的postProcess处理图片,并显示图片
ProcessAndDisplayImageTask displayTask = new ProcessAndDisplayImageTask(engine, bmp, imageLoadingInfo,
defineHandler(options));
//同步或者异步执行displayTask,加载并显示图片
if (options.isSyncLoading()) {
displayTask.run();
} else {
engine.submit(displayTask);
}
} else {
//直接显示图片,并回调正在显示接口
options.getDisplayer().display(bmp, imageAware, LoadedFrom.MEMORY_CACHE);
listener.onLoadingComplete(uri, imageAware.getWrappedView(), bmp);
}
} else {
//硬盘或者网络加载时是否显示默认图片
if (options.shouldShowImageOnLoading()) {
imageAware.setImageDrawable(options.getImageOnLoading(configuration.resources));
} else if (options.isResetViewBeforeLoading()) {
imageAware.setImageDrawable(null);
}
//生成图片加载信息
ImageLoadingInfo imageLoadingInfo = new ImageLoadingInfo(uri, imageAware, targetSize, memoryCacheKey,
options, listener, progressListener, engine.getLockForUri(uri));
//从硬盘或者网络加载图片
LoadAndDisplayImageTask displayTask = new LoadAndDisplayImageTask(engine, imageLoadingInfo,
defineHandler(options));
//同步或者异步执行displayTask,加载并显示图片
if (options.isSyncLoading()) {
displayTask.run();
} else {
engine.submit(displayTask);
}
}
}
2.LoadAndDisplayImageTask
public void run() {
if (waitIfPaused()) return;
if (delayIfNeed()) return;
ReentrantLock loadFromUriLock = imageLoadingInfo.loadFromUriLock;
L.d(LOG_START_DISPLAY_IMAGE_TASK, memoryCacheKey);
if (loadFromUriLock.isLocked()) {
L.d(LOG_WAITING_FOR_IMAGE_LOADED, memoryCacheKey);
}
//加载锁上锁
loadFromUriLock.lock();
Bitmap bmp;
try {
checkTaskNotActual();
//尝试从内存中根据Bitmap的键加载
bmp = configuration.memoryCache.get(memoryCacheKey);
if (bmp == null || bmp.isRecycled()) {
//从硬盘或者网络中加载!!!!!!!
bmp = tryLoadBitmap();
if (bmp == null) return; // listener callback already was fired
checkTaskNotActual();
checkTaskInterrupted();
//调用preProcessor进行图片处理 preProcessor处理完的图放入内存
if (options.shouldPreProcess()) {
L.d(LOG_PREPROCESS_IMAGE, memoryCacheKey);
bmp = options.getPreProcessor().process(bmp);
if (bmp == null) {
L.e(ERROR_PRE_PROCESSOR_NULL, memoryCacheKey);
}
}
//如果设置了内存缓存,则将图片存入内存
if (bmp != null && options.isCacheInMemory()) {
L.d(LOG_CACHE_IMAGE_IN_MEMORY, memoryCacheKey);
configuration.memoryCache.put(memoryCacheKey, bmp);
}
} else {
//否则从缓存加载
loadedFrom = LoadedFrom.MEMORY_CACHE;
L.d(LOG_GET_IMAGE_FROM_MEMORY_CACHE_AFTER_WAITING, memoryCacheKey);
}
//如何设置了PostProcessor,则执行PostProcessor PostProcessor是从内存中拿出后进行的处理
if (bmp != null && options.shouldPostProcess()) {
L.d(LOG_POSTPROCESS_IMAGE, memoryCacheKey);
bmp = options.getPostProcessor().process(bmp);
if (bmp == null) {
L.e(ERROR_POST_PROCESSOR_NULL, memoryCacheKey);
}
}
checkTaskNotActual();
checkTaskInterrupted();
} catch (TaskCancelledException e) {
fireCancelEvent();
return;
} finally {
//加载锁解锁
loadFromUriLock.unlock();
}
//显示图片
DisplayBitmapTask displayBitmapTask = new DisplayBitmapTask(bmp, imageLoadingInfo, engine, loadedFrom);
runTask(displayBitmapTask, syncLoading, handler, engine);
}
3.tryLoadBitmap() 真正加载使用的方法
private Bitmap tryLoadBitmap() throws TaskCancelledException {
Bitmap bitmap = null;
try {
//尝试在文件中加载
File imageFile = configuration.diskCache.get(uri);
if (imageFile != null && imageFile.exists() && imageFile.length() > 0) {
L.d(LOG_LOAD_IMAGE_FROM_DISK_CACHE, memoryCacheKey);
loadedFrom = LoadedFrom.DISC_CACHE;
checkTaskNotActual();
//从文件中解码图片
bitmap = decodeImage(Scheme.FILE.wrap(imageFile.getAbsolutePath()));
}
if (bitmap == null || bitmap.getWidth() <= 0 || bitmap.getHeight() <= 0) {
L.d(LOG_LOAD_IMAGE_FROM_NETWORK, memoryCacheKey);
//内存和硬盘都没有,只能从网络中下载图片
loadedFrom = LoadedFrom.NETWORK;
String imageUriForDecoding = uri;
if (options.isCacheOnDisk() && tryCacheImageOnDisk()) {
imageFile = configuration.diskCache.get(uri);
if (imageFile != null) {
imageUriForDecoding = Scheme.FILE.wrap(imageFile.getAbsolutePath());
}
}
checkTaskNotActual();
//从网络解码图片
bitmap = decodeImage(imageUriForDecoding);
if (bitmap == null || bitmap.getWidth() <= 0 || bitmap.getHeight() <= 0) {
fireFailEvent(FailType.DECODING_ERROR, null);
}
}
} catch (IllegalStateException e) {
fireFailEvent(FailType.NETWORK_DENIED, null);
} catch (TaskCancelledException e) {
throw e;
} catch (IOException e) {
L.e(e);
fireFailEvent(FailType.IO_ERROR, e);
} catch (OutOfMemoryError e) {
L.e(e);
fireFailEvent(FailType.OUT_OF_MEMORY, e);
} catch (Throwable e) {
L.e(e);
fireFailEvent(FailType.UNKNOWN, e);
}
return bitmap;
}
3.ProcessAndDisplayImageTask
内存加载类功能相对简单,只需要进行一次PostProcess,然后显示到控件即可。
@Override
public void run() {
L.d(LOG_POSTPROCESS_IMAGE, imageLoadingInfo.memoryCacheKey);
//执行postProcessor
BitmapProcessor processor = imageLoadingInfo.options.getPostProcessor();
Bitmap processedBitmap = processor.process(bitmap);
//将图片显示到控件上
DisplayBitmapTask displayBitmapTask = new DisplayBitmapTask(processedBitmap, imageLoadingInfo, engine,
LoadedFrom.MEMORY_CACHE);
LoadAndDisplayImageTask.runTask(displayBitmapTask, imageLoadingInfo.options.isSyncLoading(), handler, engine);
}
总结
可以ImageLoader依然是使用我们比较熟悉的内存缓存-硬盘缓存-网络加载模式。通过对加载过程与相关数据的封装,增强了程序的可扩展性。通过不同的类管理不同的线程以及不同的功能,达到灵活修改功能的目的,使程序方便扩展。今天就写到这里吧。