UniversalImageLoader源码解析之任务处理
来源:互联网 发布:药天下软件 编辑:程序博客网 时间:2024/06/09 19:57
转载请注明出处:http://blog.csdn.net/crazy1235/article/details/70471293
- ProcessAndDisplayImageTask
- LoadAndDisplayImageTask
上篇文章介绍 displayImage() 这个重要的方法时,重要涉及到 ProcessAndDisplayImageTask (处理和显示图片任务)和 LoadAndDisplayImageTask(加载显示图片任务) 这两个任务。
先来看下 ProcessAndDisplayImageTask
ProcessAndDisplayImageTask
displayImage() 中,当从内存缓存中读取到bitmap,然后需要后续处理的时候,创建了 ProcessAndDisplayImageTask 对象
ProcessAndDisplayImageTask displayTask = new ProcessAndDisplayImageTask(engine, bmp, imageLoadingInfo, defineHandler(options));
defineHandler()
private static Handler defineHandler(DisplayImageOptions options) { Handler handler = options.getHandler(); if (options.isSyncLoading()) { handler = null; } else if (handler == null && Looper.myLooper() == Looper.getMainLooper()) { handler = new Handler(); } return handler; }
从上面代码可以看出,当需要同步加载时,handler = null 。异步加载时,创建了一个 MainLooper 下的一个handler对象。
下面来看 ProcessAndDisplayImageTask 的类内部结构!
final class ProcessAndDisplayImageTask implements Runnable { private static final String LOG_POSTPROCESS_IMAGE = "PostProcess image before displaying [%s]"; private final ImageLoaderEngine engine; private final Bitmap bitmap; private final ImageLoadingInfo imageLoadingInfo; private final Handler handler; public ProcessAndDisplayImageTask(ImageLoaderEngine engine, Bitmap bitmap, ImageLoadingInfo imageLoadingInfo, Handler handler) { this.engine = engine; this.bitmap = bitmap; this.imageLoadingInfo = imageLoadingInfo; this.handler = handler; } @Override public void run() { L.d(LOG_POSTPROCESS_IMAGE, imageLoadingInfo.memoryCacheKey); BitmapProcessor processor = imageLoadingInfo.options.getPostProcessor(); Bitmap processedBitmap = processor.process(bitmap); // 创建了DisplayBitmapTask 对象 DisplayBitmapTask displayBitmapTask = new DisplayBitmapTask(processedBitmap, imageLoadingInfo, engine, LoadedFrom.MEMORY_CACHE); LoadAndDisplayImageTask.runTask(displayBitmapTask, imageLoadingInfo.options.isSyncLoading(), handler, engine); }}
重点看 run() 方法!
其实UIL库内部并没有 BitmapProecssor 的默认实现!所以displayImage() 方法内部直接走else分支,显示图片并回调成功函数!
所以需要post处理的时候就要自己写实现方法来做!
我们分析的时候假定 options.shouldPostProcess() == true
在ProcessAndDisplayImageTask 的run方法内部,post处理完bitmap之后,创建了 DisplayBitmapTask 对象!
final class DisplayBitmapTask implements Runnable { private static final String LOG_DISPLAY_IMAGE_IN_IMAGEAWARE = "Display image in ImageAware (loaded from %1$s) [%2$s]"; private static final String LOG_TASK_CANCELLED_IMAGEAWARE_REUSED = "ImageAware is reused for another image. Task is cancelled. [%s]"; private static final String LOG_TASK_CANCELLED_IMAGEAWARE_COLLECTED = "ImageAware was collected by GC. Task is cancelled. [%s]"; private final Bitmap bitmap; private final String imageUri; private final ImageAware imageAware; private final String memoryCacheKey; private final BitmapDisplayer displayer; private final ImageLoadingListener listener; private final ImageLoaderEngine engine; private final LoadedFrom loadedFrom; public DisplayBitmapTask(Bitmap bitmap, ImageLoadingInfo imageLoadingInfo, ImageLoaderEngine engine, LoadedFrom loadedFrom) { this.bitmap = bitmap; imageUri = imageLoadingInfo.uri; imageAware = imageLoadingInfo.imageAware; memoryCacheKey = imageLoadingInfo.memoryCacheKey; displayer = imageLoadingInfo.options.getDisplayer(); listener = imageLoadingInfo.listener; this.engine = engine; this.loadedFrom = loadedFrom; } @Override public void run() { if (imageAware.isCollected()) { L.d(LOG_TASK_CANCELLED_IMAGEAWARE_COLLECTED, memoryCacheKey); listener.onLoadingCancelled(imageUri, imageAware.getWrappedView()); } else if (isViewWasReused()) { L.d(LOG_TASK_CANCELLED_IMAGEAWARE_REUSED, memoryCacheKey); listener.onLoadingCancelled(imageUri, imageAware.getWrappedView()); } else { L.d(LOG_DISPLAY_IMAGE_IN_IMAGEAWARE, loadedFrom, memoryCacheKey); displayer.display(bitmap, imageAware, loadedFrom); engine.cancelDisplayTaskFor(imageAware); listener.onLoadingComplete(imageUri, imageAware.getWrappedView(), bitmap); } } /** Checks whether memory cache key (image URI) for current ImageAware is actual */ private boolean isViewWasReused() { String currentCacheKey = engine.getLoadingUriForView(imageAware); return !memoryCacheKey.equals(currentCacheKey); }}
该类也很简单!重点就在run()函数!就是经过判断回调加载成功、失败、去掉回调函数!
最后调用了LoadAndDisplayImageTask 函数的一个静态方法! runTask()
LoadAndDisplayImageTask.runTask(displayBitmapTask, imageLoadingInfo.options.isSyncLoading(), handler, engine);
static void runTask(Runnable r, boolean sync, Handler handler, ImageLoaderEngine engine) { if (sync) { r.run(); } else if (handler == null) { engine.fireCallback(r); } else { handler.post(r); } }
当需要同步加载时直接运行 DisplayBitmapTask 的run方法,进而回调函数显示bitmap!
不需要同步加载时,调用了 handler.post(handler) 方法!由hanler机制异步回调处理!
分析到这里,从缓存中读取bitmap进而显示的流程就分析完毕了!
接下来看 LoadAndDisplayImageTask
LoadAndDisplayImageTask
该类的作用是加载并显示图片,实现了Runnable接口,用于从网络、文件系统或内存获取图片并解析,然后调用DisplayBitmapTask显示图片。
@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(); // // 1. 从内存缓存中读取bitmap bmp = configuration.memoryCache.get(memoryCacheKey); if (bmp == null || bmp.isRecycled()) { // 2. 内存缓存中读取失败时,调用tryLoadBitmap(); bmp = tryLoadBitmap(); if (bmp == null) return; // listener callback already was fired checkTaskNotActual(); // checkTaskInterrupted(); // // 3. 缓存之前的处理 if (options.shouldPreProcess()) { L.d(LOG_PREPROCESS_IMAGE, memoryCacheKey); bmp = options.getPreProcessor().process(bmp); if (bmp == null) { L.e(ERROR_PRE_PROCESSOR_NULL, memoryCacheKey); } } // 4. 需要缓存到内存时保存 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); } // 5. bitmap显示之前的处理 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(); } // 6. 同样是创建的DisplayBitmapTask 任务 DisplayBitmapTask displayBitmapTask = new DisplayBitmapTask(bmp, imageLoadingInfo, engine, loadedFrom); //7. 调用该类内部的静态方法runTask 显示图片 runTask(displayBitmapTask, syncLoading, handler, engine); }
先来说下下面几个函数
- waitIfPaused()
private boolean waitIfPaused() { AtomicBoolean pause = engine.getPause(); if (pause.get()) { synchronized (engine.getPauseLock()) { if (pause.get()) { L.d(LOG_WAITING_FOR_RESUME, memoryCacheKey); try { engine.getPauseLock().wait(); } catch (InterruptedException e) { L.e(LOG_TASK_INTERRUPTED, memoryCacheKey); return true; } L.d(LOG_RESUME_AFTER_PAUSE, memoryCacheKey); } } } return isTaskNotActual(); }
真正运行任务之前先检查任务是否被暂停!
这里使用到了java的原子操作!如果被暂停则等待!
- delayIfNeed()
private boolean delayIfNeed() { if (options.shouldDelayBeforeLoading()) { try { Thread.sleep(options.getDelayBeforeLoading()); // !!! } catch (InterruptedException e) { return true; } return isTaskNotActual(); } return false; }
如果需要延迟加载,则暂停线程等待!
- checkTaskNotActual()
用来检查view是否被回收或者重用!如果有则抛异常!退出
private void checkTaskNotActual() throws TaskCancelledException { checkViewCollected(); checkViewReused(); }
private void checkViewCollected() throws TaskCancelledException { if (isViewCollected()) { throw new TaskCancelledException(); // 抛出异常!!! } } private boolean isViewCollected() { if (imageAware.isCollected()) { L.d(LOG_TASK_CANCELLED_IMAGEAWARE_COLLECTED, memoryCacheKey); return true; } return false; }
private void checkViewReused() throws TaskCancelledException { if (isViewReused()) { throw new TaskCancelledException(); } } // 当从imageAware获取到的缓存key与当前的key不一致时就判定为当前imageAware被重用了! private boolean isViewReused() { String currentCacheKey = engine.getLoadingUriForView(imageAware); boolean imageAwareWasReused = !memoryCacheKey.equals(currentCacheKey); if (imageAwareWasReused) { L.d(LOG_TASK_CANCELLED_IMAGEAWARE_REUSED, memoryCacheKey); return true; } return false; }
- checkTaskInterrupted()
private void checkTaskInterrupted() throws TaskCancelledException { if (isTaskInterrupted()) { throw new TaskCancelledException(); } } private boolean isTaskInterrupted() { if (Thread.interrupted()) { L.d(LOG_TASK_INTERRUPTED, memoryCacheKey); return true; } return false; }
当线程被interrupted的时候也是抛出异常 – TaskCancelledException!!
OK,此时在看LoadAndDisplayImageTask 的run 函数就比较明了了!
来看一张LoadAndDisplayImageTask的内部函数调用流程图!!
https://github.com/crazy1235/About-Image/tree/master/UniversalImageLoaderDemo
OVER!
- UniversalImageLoader源码解析之任务处理
- UniversalImageLoader源码解析之 DiskCache
- UniversalImageLoader源码解析之 MomoryCache
- UniversalImageLoader源码解析之总体流程
- UniversalImageLoader源码解读06-任务调度
- UniversalImageLoader 源码解析 -1.enam(枚举)使用
- UniversalImageLoader源码分析之二、示例分析
- UniversalImageLoader源码解读02-图片处理和显示
- Android异步任务之AsyncTask源码解析
- Android AsyncTask 异步任务之源码解析
- UniversalImageLoader 源码笔记(1)
- universalimageloader 最新版解析
- Spark特征处理之RFormula源码解析
- Android源码解析之(三)-->异步任务AsyncTask
- Android源码基础解析之异步任务AsyncTask
- Spark源码解析之任务提交(spark-submit)篇
- UniversalImageLoader
- UniversalImageLoader
- python使用ctypes和pywin32访问原生API
- Django学习5-url配置
- spring 使用构造器方式依赖注入
- 在Android5.1系统源码中加入测试APP应用程序
- PHP入门之开发环境搭建
- UniversalImageLoader源码解析之任务处理
- log4j的配置文件的内容
- kscope
- Mac 磁盘自动增加,越来越小的问题
- Java异常体系结构 .
- Aurelia快速搭建
- java web监听器
- [Wechall]Training:MySQL
- 编写高效且优雅的 Python 代码