在《ImageLoader的简单分析》这篇博客中对IImageLoader三大组件的创建过程以及三者之间的关系做了说明,同时文章的最后也简单的说明了一下ImageLoader是怎么通过displayImage方法来获取缓存来显示图片的,本文就对ImageLoader的这个知识点做较为详细的说明。
ImageLoader对缓存的使用还是很灵活的:支持同步或者异步加载图片资源,对内存缓存和文件缓存可以选择使用其一或者二者都是用。在构建DisplayImageOptions对象的时候可以通过cacheInMemory(true)、cacheOnDisk(true)两个方法来灵活选择到底使用哪一种缓存策略。另外组件ImageLoaderConfiguration的时候也可配置自定义的内存缓存、文件缓存的具体实现方式。也就是说 ImageLoaderCofiguration的功能之一就是提供了内存缓存和硬件缓存的具体方式配置,但是是否需要对图片进行内存缓存或者文件缓存则是由DisplayImageOptions来决定的。

如何读取使用缓存?

在ImageLoader的实现中如果图片资源Uri不为null的情况下,会先从memory cache里面读取出Bitmap对象,然后使用之,代码如下:

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自定义的Displyer显示SimpleBitmapDisplayeroptions.getDisplayer().display(bmp, imageAware, LoadedFrom.MEMORY_CACHE);listener.onLoadingComplete(uri, imageAware.getWrappedView(), bmp);}

可以看出ImageLoader对Bitmap对象的使用也很灵活:你可以直接从缓存中取出Bitmap对象然后使用之,也可以把读取到的Bitmap设置给ImageView之前做一些处理,比如对bitmap添加特效,增加倒影等操作。然后把特效处理过的Bitmap交给ImageView处理!是否需要对读取的Bitmap处理是由DisplayImageOptions的postProcessor(postProcessor)来决定的,如果在组件DisplayImageOptions的过程中配置了postProcessor,那么上面的代码中if(options.shouldPostProcess())成立。在使用postProcessor的时候你需要传一个BitmapProcessor接口的实现类,这个接口也很简单就是提供了Bitmap process(Bitmap bitmap)方法,方法参数里面的bitmap就是从缓存中读取到的Bitmap对象,该方法返回经过“特效”处理过的Bitmap,然后就交给ImageView处理了,同时对通过process对bitmap的处理也支持同步和异步操作。
1)把ImageView,memoryCache等信息封装成ImageLoadingInfo 对象。
2)把ImageLoadingInfo 对象交给ProcessAndDisplayImageTask,见名知意,这个对象就是使ImageView显示图片的,是一个Ruannable。
3)根据是异步还是同步加载来执行process来处理Bitmap后显示图片,同步与否仍然在DisplayImageOptions类配置,默认是异步。当然异步只是把这个Runnable交给ImageLoader内部的线程来处理,同步则直接运行Ruannable的run方法,所以在此我们直接分析ProcessAndDisplayImageTask的run方法,看看它具体做了什么!

@Overridepublic void run() {BitmapProcessor processor = imageLoadingInfo.options.getPostProcessor();//调用自动以的BitmapProcessor处理器对bitMap进行处理,并将处理过的bitmap交给imageView显示Bitmap processedBitmap = processor.process(bitmap);DisplayBitmapTask displayBitmapTask = new DisplayBitmapTask(processedBitmap, imageLoadingInfo, engine,LoadedFrom.MEMORY_CACHE);//实际显示图片的地方的地方LoadAndDisplayImageTask.runTask(displayBitmapTask, imageLoadingInfo.options.isSyncLoading(), handler, engine);}

如上代码所示,ProcessAndDisplayImageTask代码结构也很清晰,具体做了如下三个工作:
1)获取DisplayImageOptions配置的BitmapProcessor 对象(注意是通过getPostProcessor方法获取的,后面还会提到getPreProcessor方法.
2)执行BitmapProcessor 的process方法对Bitmap进行加工处理,并返回之。
3)将加工过的Bitmap传给DisplayBitmapTask对象,该对象也是一个Runnable。
4)将DisplayBitmapTask交给LoadAndDisplayImageTask这个类的runTask方法,并执行;这个runTask方法正是ImageView正式显示图片的方法所在!
那么就让我们看看这个方法又做了些神马:

static void runTask(Runnable r, boolean sync, Handler handler, ImageLoaderEngine engine) {//如果是同步if (sync) {r.run();} else if (handler == null) {//ImageLoader开启一个线程加载engine.fireCallback(r);} else {//如果定义了handler,显示文件的逻辑交给handler.post(r);}}

刚方法也很简单,主要做了如下工作
1)如果是同步的话直接运行DisplayBitmapTask这个Runnable的run方法
2)如果是异步并且你的DisplayImageOptions没有配置handler,就用engine.fireCallback(r);让ImageLoader定义的异步加载机制完成异步操作
3)如果在组件DisplayImageOptions的时候通过handler(Handerl handler)配置了你自己的handler,那么就交给post(r);
在我开发的项目时候倒是没有配置handler那么就说明项目中是异步执行了DisplayBitmapTask这个Runnable,所以有需要分析这个Runnable都做了些神马:

@Overridepublic void run() {if (imageAware.isCollected()) {//如果被垃圾回收        listener.onLoadingCancelled(imageUri, imageAware.getWrappedView());} else if (isViewWasReused()) {listener.onLoadingCancelled(imageUri, imageAware.getWrappedView());} else {//实际上是调用SimpleBitmapDisplayer方法displayer.display(bitmap, imageAware, loadedFrom);engine.cancelDisplayTaskFor(imageAware);listener.onLoadingComplete(imageUri, imageAware.getWrappedView(), bitmap);}}

在这里我们直接分析最后的else分支,可以发现ImageLoader最终是通过displayer这个对象的display方法来完成ImageView的图片的显示的,同时让listener执行onLoadingComplete来告知客户端图片已经加载完成,可以在onLoadingComplete方法中做一些额外的处理。
那么这个Displayer对象是何许人也?在DisplayBitmapTask这个类的构造器中是这么对Displayer来完成初始化的:

//DisplayImageOptions的getDisplayer
displayer = imageLoadingInfo.options.getDisplayer();

所以这个对象最初初始化的地方仍然是DisplayImageOptions;那么我们就要看看DisplayImageOptions这个类里面是怎么初始化displayer的。在DisplayImageOptions的构造器有这么段代码:

private final BitmapDisplayer displayer;
DisplayImageOptions(Builder builder){
displayer = builder.displayer;
}

啥都不说了既然是Builder在构建DisplayImageOptions对象的过程中初始化了displayer,而通常在使用Builder组件DisplayImageOptions的过程中基本上不会手动配置BitmapDisplayer 这个对象,所以Builder肯定会默认对其初始化。代码体现如下:

private BitmapDisplayer displayer = DefaultConfigurationFactory.createBitmapDisplayer();public static BitmapDisplayer createBitmapDisplayer() {return new SimpleBitmapDisplayer();}

所以最终返回的是SimpleBitmapDisplayer对象,通过该对象的display方法来完成ImageView展示图片的功。所以谜底马上揭晓,让我们看看display方法都干了什么了不起的事儿:

@Overridepublic void display(Bitmap bitmap, ImageAware imageAware, LoadedFrom loadedFrom) {imageAware.setImageBitmap(bitmap);}

So easy!就是把生成的Bitmap交给了imageAware对象的setImageBitmap方法来处理!还记得之前说过调用ImageLoader的displayImage(uri,ImageView)方法会把ImageView会把包装成ImageViewAware对象,那么此处的imageAware正式我们的目标ImageView!!!所以既然都到这了,还是乖乖看setImageBitmap方法的具体实现吧!

//此方法在ImageViewAware的父类ViewAware中。public boolean setImageBitmap(Bitmap bitmap) {//回到我们熟悉的UI线程啦if (Looper.myLooper() == Looper.getMainLooper()) {View view = viewRef.get();if (view != null) {//调用setImageBitmapInto方法来最终显示setImageBitmapInto(bitmap, view);return true;}} else {L.w(WARN_CANT_SET_BITMAP);}return false;}

我屮艸芔茻!!!怎么还没看到ImageView怎么显示的呢?最终又要调用setImageBitmapInto,日了狗了,有种放长线掉到了大鱼的感觉:

    @Overrideprotected void setImageBitmapInto(Bitmap bitmap, View view) {((ImageView) view).setImageBitmap(bitmap);}

souga,最终就是把调用了ImageView的setImageBitmap方法而已!
啰嗦了一大堆还是对ImageView从内存缓存中获取Bitmap并显示出来的过程总结比较好:
1)从ImageLoader的memory cache中读取出Bitmap对象
2)判断是否需要对生成的Bitmap对象做处理,如果不需要跳到步骤4,否则执行步骤3
3)是否是异步操作,如果是异步操作则开启ImageLoader的内部异步机制完成了对bitmap处理后跳转到步骤4,否则同步对bitmap处理后跳转到步骤4
4)用SimpleBitmapDisplayer对象的display方法最终调用ImageView的setImageBitmap来展示图像。
最后用流程图来直观表示就是如下所示了:

到此为止,本篇博客结束,至于对文件缓存以及下载网络图片资源的流程限于篇幅,将另外开一篇博客来做说明,如有错误不当之处,欢迎批评指正。

ImageLoader的简单分析(二)相关推荐

  1. 掘金15W沸点简单分析(二)

    一.数据预处理与入库 获取到了原始数据之后,下一步就是清洗入库. 1.1 数据模型 因为是简单分析,所以只获取话题.用户.消息三块内容.具体如下: class Pins(object):"& ...

  2. 【RuoYi-Vue-Plus】学习笔记 46 - Redisson(十二)布隆过滤器 BloomFilter 简单分析

    文章目录 前言 参考目录 测试方法 配置说明 Demo 方法 功能调用流程分析 1.布隆过滤器的初始化 `tryInit` 1.1.创建布隆过滤器 1.2.初始化布隆过滤器 1.2.1.计算 bit ...

  3. 二维正态分布图python代码_Python数据可视化正态分布简单分析及实现代码

    Python说来简单也简单,但是也不简单,尤其是再跟高数结合起来的时候... 正态分布(Normaldistribution),也称"常态分布",又名高斯分布(Gaussiandi ...

  4. Mac与Phy组成原理的简单分析

    Mac与Phy组成原理的简单分析 2011-12-28 15:30:43 //http://blog.chinaunix.net/uid-20528014-id-3050217.html 本文乃fir ...

  5. modem (1)---手机主叫的信道流程与Modem Log简单分析

    手机主叫的信道流程与Modem Log简单分析 层三信令里看到建立RRCCMM层什么的到底是什么意思?建立这些层有什么用? 从协议栈的角度来说,RR属于接入层,而MM和CC都属于非接入层即NAS. R ...

  6. Python数据挖掘学习笔记】九.回归模型LinearRegression简单分析氧化物数据

    #2018-03-23 16:26:20 March Friday the 12 week, the 082 day SZ SSMR [Python数据挖掘学习笔记]九.回归模型LinearRegre ...

  7. x264源代码简单分析:宏块编码(Encode)部分

    ===================================================== H.264源代码分析文章列表: [编码 - x264] x264源代码简单分析:概述 x26 ...

  8. x264源代码简单分析:x264_slice_write()

    ===================================================== H.264源代码分析文章列表: [编码 - x264] x264源代码简单分析:概述 x26 ...

  9. FFmpeg的H.264解码器源代码简单分析:宏块解码(Decode)部分-帧内宏块(Intra)

    ===================================================== H.264源代码分析文章列表: [编码 - x264] x264源代码简单分析:概述 x26 ...

  10. SpringBoot源码分析(二)之自动装配demo

    SpringBoot源码分析(二)之自动装配demo 文章目录 SpringBoot源码分析(二)之自动装配demo 前言 一.创建RedissonTemplate的Maven服务 二.创建测试服务 ...

最新文章

  1. jquery插件制作
  2. Linux下mysqldump的使用
  3. 9012年大厂面试题合集:Java技术栈为什么竞争越来越激烈?
  4. Apache并发处理模块
  5. java 域的隐藏_Windows Server 2008R2\2012\2016使用域策略自定义隐藏指定驱动器
  6. 遇到oracle错误1012,跟着感觉走,解决安装RAC过程中OCR完整性错误,待深入剖析...
  7. “神兽”出笼谁来管?多地试水暑期托管班
  8. flacs 安装教程_文章详细信息
  9. hdu5187 奇怪题
  10. 并发控制技术手段之时间戳(二)
  11. 自己动手写操作系统(高清图书+源代码)分享
  12. mathtype——小白安装
  13. c语言考试题库大一下学期基础,c语言考试题(全国c语言二级考试题库)
  14. android 阿里hotfix,Android 热修复方案--阿里百川HotFix
  15. C# 读取Word文本框中的文本、图片和表格(附VB.NET代码)
  16. 求球体的表面积和体积
  17. 计算机显示错误屏幕,如何解决显示器分辨率错误
  18. 梦幻西游网页版服务器,服务器荣辱战,《梦幻西游网页版》梦幻攻防战“挖矿人”经验来啦...
  19. html段落间距怎么缩小,WPS怎样缩小段落间距
  20. 公司技术分享-全文技术分享Lucene VS ElasticSearch VS Solr

热门文章

  1. JavaWeb:cookies和storage的区别
  2. JavaScript:设置网站title
  3. ElementUI:vue中使用elementUI时候通过SCSS修改NavMenu 导航栏高度
  4. FNV摘要HASH算法实战
  5. 一个简单的十年回顾及展望
  6. ML/DL-复习笔记【三】- 算法的评价指标
  7. 非递归方式对二叉树进行前序、中序、后序遍历(C++实现)
  8. ESPNet: Efficient Spatial Pyramid of Dilated Convolutions for Semantic Segmentation(自动驾驶领域轻量级模型)
  9. 在一个长度为n的数组里的所有数字都在0到n-1的范围内。 数组中某些数字是重复的,但不知道有几个数字是重复的。也不知道每个数字重复几次。请找出数组中任意一个重复的数字。
  10. 关于C++中的继承感悟