universal-image-loader源码解析
2017-05-21 20:41
288 查看
一.执行流程:
首先我们是配置好configuration和displayOptions,然后进入到displayImage方法里来.
1.检查缓存里是否有图片
2.没有的话,将传进来的参数与option一起包装成ImageloadingInfo类
3.传入LoadAndDisplayImage里通过Engine类进行加载执行.
5.在LoadAndDisplayImage类里的tryloadImage方法里,我们可以看到这个ImageloadingInfo再次被包装成ImageDecodingInfo传入ImageDecoder里.
6.ImageDecoder将信息传到ImageDownloader里,进行下载.
7.下载完成后或者解码完图片后,再把它放到Imageaware里进行显示.
8.但真正的显示是BitmapDisplay类来执行的.
二.类功能大体分析(详细分析后面会写)
1.cache文件:缓存策略的实现
2.ImageLoaderConfiguration:一些配置信息,主要是对线程的限制.
3.DefaultConfigurationFactory:使用工厂方法模式实现的默认的配置信息.
4.DisplayImageOptions:顾名思义啊,就是图片显示时你要对它做的一些要求.
5.ImageLoadingInfo:对options和一些值进行包装的一个数据类.
6.三个Task类:runnable的实现类,用于图片的耗时操作.
7.process文件夹:可以用它的接口来自定义对图片的处理.
8.listener文件夹:用于监听事件,并作出处理,还有进度条的监听.
9.Imageaware文件夹+display文件夹:对图片的显示进行处理.
10.decode:对获取到的图片进行解码处理,返回一个bitmap.
11.download:对uri进行加载,并获取到inputstream,返回给decode.
12.assist:一些enum类,还有对输入流作出一些自定义操作的类.还有自定义了一些双向队列.
三.详细分析:
从Imageloader类里的DisplayImage方法,我们可以跟踪得到它的执行过程:
这个方法的执行过程大体就是
1.判断相应的配置信息是否为空2.从内存中获取图片,得到并进入processandDisplayImage类中对图片进行处理3.在内存中无图片,进入loadAndDisplayImage类中执行.
因为Imageloader使用的是门面模式,它很好的反应了流程,但是具体的执行细节,还要进入具体类.从上面的方法中,我们可以发现ImageLoadEngine类和loadAndDisplayImage类和processandDisplayImage类出现.
ImageLoadEngine类如下: 类中有三个Executor变量,可见是要对相关的线程进行执行.从displayImage方法里看到有engine.submit(displayTask)这句.在ImageLoaderEngine类的submit方法中,我们看到就是单纯的Executor对task(实际为Runnable)的执行.所以此类是一个执行类,我们继续深入到loadAndDisplayImage类中.
loadAndDisplayImage类主要代码如下:
这个类才是真正的应用三级缓存对图片进行加载操作的类,先看是否在内存中有,没有就进入diskCache中,再没有才进行网络的下载,将下载好的图片再放入到diskCache中,再从中获取.当没有在内存和diskCache中找到图片时,我们回去网络加载,所以就得再深入到ImageDecoder类中了.
ImageDecoder类实际为一个接口,可以看到ImageDecodingInfo 是一个对要解码的对象进行包装的类,ImageDecoder类的具体实现类如下:
BaseImageDecoder:
(解释在注释里)
上面说到还有一个加载类ImageDownLoader类:
它的内部使用HttpURLConnection进行图片的下载.
现在图片也下载好了,总得让它显示吧.
在上面的loadAndDisplayImageTask的run方法最后有一段这样的代码,可见DisplayBitmapTask 应该就是显示任务的线程类了.
DisplayBitmapTask 类如下:
看这句 displayer.display(bitmap, imageAware, loadedFrom); BitmapDisplayer就是显示类.
来看BitmapDisplayer类: 一个接口.
这里就不对它的实现类进行分析了,这里可以继承它,并且在图片显示的时候,让它进行个性化的显示,比如说将图片显示成圆形的等.
最后了,得有个容器装bitmap吧,不然bitmap在什么上显示了,至少也得在ImageView上吧.
作者对ImageView进行包装, 使用弱引用,可以对其进行回收,在ViewAware虚类中有.
ImageAware接口,具体的实现类是ImageViewAware,主要实现setImageDrawable和setImageBitmap这俩个方法.isCollected()方法判断view是否被回收.
首先我们是配置好configuration和displayOptions,然后进入到displayImage方法里来.
1.检查缓存里是否有图片
2.没有的话,将传进来的参数与option一起包装成ImageloadingInfo类
3.传入LoadAndDisplayImage里通过Engine类进行加载执行.
5.在LoadAndDisplayImage类里的tryloadImage方法里,我们可以看到这个ImageloadingInfo再次被包装成ImageDecodingInfo传入ImageDecoder里.
6.ImageDecoder将信息传到ImageDownloader里,进行下载.
7.下载完成后或者解码完图片后,再把它放到Imageaware里进行显示.
8.但真正的显示是BitmapDisplay类来执行的.
二.类功能大体分析(详细分析后面会写)
1.cache文件:缓存策略的实现
2.ImageLoaderConfiguration:一些配置信息,主要是对线程的限制.
3.DefaultConfigurationFactory:使用工厂方法模式实现的默认的配置信息.
4.DisplayImageOptions:顾名思义啊,就是图片显示时你要对它做的一些要求.
5.ImageLoadingInfo:对options和一些值进行包装的一个数据类.
6.三个Task类:runnable的实现类,用于图片的耗时操作.
7.process文件夹:可以用它的接口来自定义对图片的处理.
8.listener文件夹:用于监听事件,并作出处理,还有进度条的监听.
9.Imageaware文件夹+display文件夹:对图片的显示进行处理.
10.decode:对获取到的图片进行解码处理,返回一个bitmap.
11.download:对uri进行加载,并获取到inputstream,返回给decode.
12.assist:一些enum类,还有对输入流作出一些自定义操作的类.还有自定义了一些双向队列.
三.详细分析:
从Imageloader类里的DisplayImage方法,我们可以跟踪得到它的执行过程:
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; } 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; } if (targetSize == null) { targetSize = ImageSizeUtils.defineTargetSizeForView(imageAware, configuration.getMaxImageSize()); } 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); } } }
这个方法的执行过程大体就是
1.判断相应的配置信息是否为空2.从内存中获取图片,得到并进入processandDisplayImage类中对图片进行处理3.在内存中无图片,进入loadAndDisplayImage类中执行.
因为Imageloader使用的是门面模式,它很好的反应了流程,但是具体的执行细节,还要进入具体类.从上面的方法中,我们可以发现ImageLoadEngine类和loadAndDisplayImage类和processandDisplayImage类出现.
ImageLoadEngine类如下: 类中有三个Executor变量,可见是要对相关的线程进行执行.从displayImage方法里看到有engine.submit(displayTask)这句.在ImageLoaderEngine类的submit方法中,我们看到就是单纯的Executor对task(实际为Runnable)的执行.所以此类是一个执行类,我们继续深入到loadAndDisplayImage类中.
private Executor taskExecutor;//用于加载图片 private Executor taskExecutorForCac 4000 hedImages;//用于处理图片 private Executor taskDistributor;//用于分发 void submit(final LoadAndDisplayImageTask task) { taskDistributor.execute(new Runnable() { @Override public void run() { File image = configuration.diskCache.get(task.getLoadingUri()); boolean isImageCachedOnDisk = image != null && image.exists(); initExecutorsIfNeed(); if (isImageCachedOnDisk) { taskExecutorForCachedImages.execute(task); } else { taskExecutor.execute(task); } } }); } /** Submits task to execution pool */ void submit(ProcessAndDisplayImageTask task) { initExecutorsIfNeed(); taskExecutorForCachedImages.execute(task); }
loadAndDisplayImage类主要代码如下:
这个类才是真正的应用三级缓存对图片进行加载操作的类,先看是否在内存中有,没有就进入diskCache中,再没有才进行网络的下载,将下载好的图片再放入到diskCache中,再从中获取.当没有在内存和diskCache中找到图片时,我们回去网络加载,所以就得再深入到ImageDecoder类中了.
@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); }
ImageDecoder类实际为一个接口,可以看到ImageDecodingInfo 是一个对要解码的对象进行包装的类,ImageDecoder类的具体实现类如下:
public interface ImageDecoder { Bitmap decode(ImageDecodingInfo imageDecodingInfo) throws IOException; }
BaseImageDecoder:
(解释在注释里)
public Bitmap decode(ImageDecodingInfo decodingInfo) throws IOException { Bitmap decodedBitmap; ImageFileInfo imageInfo; //得到InputStream,通过ImageDownLoader的getStream方法,下面会介绍. InputStream imageStream = getImageStream(decodingInfo); if (imageStream == null) { L.e(ERROR_NO_IMAGE_STREAM, decodingInfo.getImageKey()); return null; } try { //返回下载后的图片的宽高,还未经处理. imageInfo = defineImageSizeAndRotation(imageStream, decodingInfo); //重置InputStream imageStream = resetStream(imageStream, decodingInfo); //根据加载后的图片的宽高与客户的要求对图片进行处理,获得缩放比,并存入options中返回. Options decodingOptions = prepareDecodingOptions(imageInfo.imageSize, decodingInfo); //解码. decodedBitmap = BitmapFactory.decodeStream(imageStream, null, decodingOptions); } finally { IoUtils.closeSilently(imageStream); } if (decodedBitmap == null) { L.e(ERROR_CANT_DECODE_IMAGE, decodingInfo.getImageKey()); } else { decodedBitmap = considerExactScaleAndOrientatiton(decodedBitmap, decodingInfo, imageInfo.exif.rotation, mageInfo.exif.flipHorizontal); } return decodedBitmap; }
上面说到还有一个加载类ImageDownLoader类:
它的内部使用HttpURLConnection进行图片的下载.
public interface ImageDownloader { InputStream getStream(String imageUri, Object extra) throws IOException; }
现在图片也下载好了,总得让它显示吧.
在上面的loadAndDisplayImageTask的run方法最后有一段这样的代码,可见DisplayBitmapTask 应该就是显示任务的线程类了.
DisplayBitmapTask displayBitmapTask = new DisplayBitmapTask(bmp, imageLoadingInfo, engine, loadedFrom); runTask(displayBitmapTask, syncLoading, handler, engine);
DisplayBitmapTask 类如下:
看这句 displayer.display(bitmap, imageAware, loadedFrom); BitmapDisplayer就是显示类.
@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); } }
来看BitmapDisplayer类: 一个接口.
public interface BitmapDisplayer { void display(Bitmap bitmap, ImageAware imageAware, LoadedFrom loadedFrom); }
这里就不对它的实现类进行分析了,这里可以继承它,并且在图片显示的时候,让它进行个性化的显示,比如说将图片显示成圆形的等.
最后了,得有个容器装bitmap吧,不然bitmap在什么上显示了,至少也得在ImageView上吧.
作者对ImageView进行包装, 使用弱引用,可以对其进行回收,在ViewAware虚类中有.
public abstract class ViewAware implements ImageAware { protected Reference<View> viewRef; }
ImageAware接口,具体的实现类是ImageViewAware,主要实现setImageDrawable和setImageBitmap这俩个方法.isCollected()方法判断view是否被回收.
public interface ImageAware { int getWidth(); int getHeight(); ViewScaleType getScaleType(); View getWrappedView(); boolean isCollected(); int getId() boolean setImageDrawable(Drawable drawable); boolean setImageBitmap(Bitmap bitmap); }
相关文章推荐
- Android-Universal-Image-Loader(UIL)源码解析(二)
- UniversalImageLoader 源码解析 -1.enam(枚举)使用
- Universal-Image-Loader源码解析
- Android 开源项目源码解析 -->Android Universal Image Loader 源码分析(十四)
- 史上最全Universal-Image-Loader源码解析————缓存篇
- Android分析Universal-Image-Loader源码解析收获
- 史上最全Universal-Image-Loader源码解析————核心代码篇
- UniversalImageLoader源码解析之总体流程
- UniversalImageLoader源码解析之任务处理
- UniversalImageLoader源码解析之 DiskCache
- Android-Universal-Image-Loader(UIL)源码解析(一)
- UniversalImageLoader源码解析之 MomoryCache
- 开源项目源码解析-Android Universal Image Loader 源码分析
- 源码解析 Universal Image Loader
- Android 开源框架Universal-Image-Loader完全解析(一)--- 基本介绍及使用
- Android 开源框架Universal-Image-Loader完全解析(一)--- 基本介绍及使用
- Android 开源框架Universal-Image-Loader完全解析(三)---源代码解读
- Android 开源框架Universal-Image-Loader完全解析(三)---源代码解读
- 转:Android 开源框架Universal-Image-Loader完全解析(二)--- 图片缓存策略详解
- Android 开源框架Universal-Image-Loader完全解析(一)--- 基本介绍及使用