主要功能
1. 多线程图片加载,无论是同步还是异步加载
2. 对图片加载的可以进行多种配置
3. 对每一个图片展示定制多种选项
4. 图片缓存在内存和磁盘中
5. 监听图片加载的过程
可以使用的uri例子
"http://site.com/image.png"// from Web
"file:///mnt/sdcard/image.png"// from SD card
"file:///mnt/sdcard/video.mp4"// from SD card (video thumbnail)
"content://media/external/images/media/13"// from content provider
"content://media/external/video/media/13"// from content provider (video thumbnail)
"assets://image.png"// from assets
"drawable://"+ R.drawable.img// from drawables (non-9patch images)
图片加载过程
这张图描述了加载过程:
1.展示图片ImageLoader.class
<pre name="code" class="java">/**
* Adds display image task to execution pool. Image will be set to ImageAware when it's turn.<br />
* <b>NOTE:</b> {@link #init(ImageLoaderConfiguration)} method must be called before this method call
*
* @param uri Image URI (i.e. "http://site.com/image.png", "file:///mnt/sdcard/image.png")
* @param imageAware {@linkplain com.nostra13.universalimageloader.core.imageaware.ImageAware Image aware view}
* which should display image
* @param options {@linkplain com.nostra13.universalimageloader.core.DisplayImageOptions Options} for image
* decoding and displaying. If <b>null</b> - default display image options
* {@linkplain ImageLoaderConfiguration.Builder#defaultDisplayImageOptions(DisplayImageOptions)
* from configuration} will be used.
* @param listener {@linkplain ImageLoadingListener Listener} for image loading process. Listener fires
* events on UI thread if this method is called on UI thread.
* @param progressListener {@linkplain com.nostra13.universalimageloader.core.listener.ImageLoadingProgressListener
* Listener} for image loading progress. Listener fires events on UI thread if this method
* is called on UI thread. Caching on disk should be enabled in
* {@linkplain com.nostra13.universalimageloader.core.DisplayImageOptions options} to make
* this listener work.
* @throws IllegalStateException if {@link #init(ImageLoaderConfiguration)} method wasn't called before
* @throws IllegalArgumentException if passed <b>imageAware</b> is null
*/
public void displayImage(String uri, ImageAware imageAware, DisplayImageOptions options,
ImageLoadingListener listener, ImageLoadingProgressListener progressListener) {
checkConfiguration();
if (imageAware == null) {
throw new IllegalArgumentException(ERROR_WRONG_ARGUMENTS);
}
if (listener == null) {
listener = emptyListener;
}
if (options == null) {
options = configuration.defaultDisplayImageOptions;
}
/**
* 判断uri是否为空
*/
if (TextUtils.isEmpty(uri)) {
//取消图片的加载任务
engine.cancelDisplayTaskFor(imageAware);
//发送图片加载开始消息
listener.onLoadingStarted(uri, imageAware.getWrappedView());
if (options.shouldShowImageForEmptyUri()) {
imageAware.setImageDrawable(options.getImageForEmptyUri(configuration.resources));
} else {
imageAware.setImageDrawable(null);
}
//发送图片加载完成消息
listener.onLoadingComplete(uri, imageAware.getWrappedView(), null);
return;
}
//获取图片的大小
ImageSize targetSize = ImageSizeUtils.defineTargetSizeForView(imageAware, configuration.getMaxImageSize());
//生成存储的一个key
String memoryCacheKey = MemoryCacheUtils.generateKey(uri, targetSize);
engine.prepareDisplayTaskFor(imageAware, memoryCacheKey);
//发送图片加载开始消息
listener.onLoadingStarted(uri, imageAware.getWrappedView());
//判断是否内存中存在这个图片
Bitmap bmp = configuration.memoryCache.get(memoryCacheKey);
if (bmp != null && !bmp.isRecycled()) {
//如果图片存在
L.d(LOG_LOAD_IMAGE_FROM_MEMORY_CACHE, memoryCacheKey);
//是否需要在显示前进行处理
if (options.shouldPostProcess()) {
//如果需要处理
ImageLoadingInfo imageLoadingInfo = new ImageLoadingInfo(uri, imageAware, targetSize, memoryCacheKey,
options, listener, progressListener, engine.getLockForUri(uri));
//创建处理图像和显示图片的任务
ProcessAndDisplayImageTask displayTask = new ProcessAndDisplayImageTask(engine, bmp, imageLoadingInfo,
defineHandler(options));
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));
if (options.isSyncLoading()) {
displayTask.run();
} else {
engine.submit(displayTask);
}
}
}
如果在图片在内存中就使用ProcessAndDisplayImageTask
如果在图片不在内存中就使用LoadAndDisplayImageTask
ProcessAndDisplayImageTask.class
@Override
public void run() {
L.d(LOG_POSTPROCESS_IMAGE, imageLoadingInfo.memoryCacheKey);
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);
}
LoadAndDisplayImageTask.class
@Override
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();
//获取内存中的图片是否存在
bmp = configuration.memoryCache.get(memoryCacheKey);
if (bmp == null || bmp.isRecycled()) {
//如果不存在或者被回收了就是尝试去加载图片
bmp = tryLoadBitmap();
if (bmp == null) return; // listener callback already was fired
checkTaskNotActual();
checkTaskInterrupted();
//是否在载入内存中进行处理
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);
}
//在显示钱是否进程处理
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);
}
private Bitmap tryLoadBitmap() throws TaskCancelledException {
Bitmap bitmap = null;
try {
//是否在磁盘中存在
File imageFile = configuration.diskCache.get(uri);
if (imageFile != null && imageFile.exists()) {
//如果存在就载入图片
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;
}