在《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显示SimpleBitmapDisplayer
options.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接口的实现类。这个接口也非常easy就是提供了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方法,看看它详细做了什么!

@Override
public 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);
}
}

刚方法也非常easy,主要做了例如以下工作

1)假设是同步的话直接运行DisplayBitmapTask这个Runnable的run方法

2)假设是异步而且你的DisplayImageOptions没有配置handler,就用engine.fireCallback(r);让ImageLoader定义的异步载入机制完毕异步操作

3)假设在组件DisplayImageOptions的时候通过handler(Handerl handler)配置了你自己的handler,那么就交给post(r);

在我开发的项目时候倒是没有配置handler那么就说明项目中是异步运行了DisplayBitmapTask这个Runnable。所以有须要分析这个Runnable都做了些神马:

@Override
public 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来告知client图片已经载入完毕,能够在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方法都干了什么了不起的事儿:

@Override
public 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。日了狗了,有种放长线掉到了大鱼的感觉:

    @Override
protected 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. python爬虫实践(二)——爬取张艺谋导演的电影《影》的豆瓣影评并进行简单分析

    学了爬虫之后,都只是爬取一些简单的小页面,觉得没意思,所以我现在准备爬取一下豆瓣上张艺谋导演的“影”的短评,存入数据库,并进行简单的分析和数据可视化,因为用到的只是比较多,所以写一篇博客当做笔记. 第 ...

  2. Jmeter接口测试-简单分析结果数、聚合报告以及图形结果(二)

    简单分析结果数.聚合报告以及图形结果 结果树 取样器结果:返回值报200,表示执行接口调试成功 请求:发送的数据 响应数据:返回的数据 Thread Name:线程组名称 Sample Start: ...

  3. 简单分析JavaScript中的面向对象

    初学JavaScript的时候有人会认为JavaScript不是一门面向对象的语言,因为JS是没有类的概念的,但是这并不代表JavaScript没有对象的存在,而且JavaScript也提供了其它的方 ...

  4. C#中异常:“The type initializer to throw an exception(类型初始值设定项引发异常)”的简单分析与解决方法

    对于C#中异常:“The type initializer to throw an exception(类型初始值设定项引发异常)”的简单分析,目前本人分析两种情况,如下: 情况一: 借鉴麒麟.NET ...

  5. SNMP报文抓取与分析(二)

    SNMP报文抓取与分析(二) SNMP报文抓取与分析(二) 1.SNMP报文表示简介 基本编码规则BER 标识域Tag表示 长度域length表示 2.SNMP报文详细分析(以一个get-respon ...

  6. SQLite入门与分析(二)---设计与概念(续)

    SQLite入门与分析(二)---设计与概念(续)   写在前面:本节讨论事务,事务是DBMS最核心的技术之一.在计算机科学史上,有三位科学家因在数据库领域的成就而获ACM图灵奖,而其中之一Jim G ...

  7. Java线程池使用和分析(二) - execute()原理

    相关文章目录: Java线程池使用和分析(一) Java线程池使用和分析(二) - execute()原理 execute()是 java.util.concurrent.Executor接口中唯一的 ...

  8. PC-lint集成于SourceInsight 范例以及简单分析;提高代码的健壮性;

    写代码之际突然想起了pc-lint这个"古董级"的代码静态分析工具;   下午机房的服务器歇菜了,没法调试游戏,刚好抽出时间来研究一下pc-lint集成在SourceInsight ...

  9. AbstractQueuedSynchronizer的简单分析

    说明:本作者是文章的原创作者,转载请注明出处:本文地址:http://www.cnblogs.com/qm-article/p/7955781.html 一.AbstractQueuedSynchro ...

随机推荐

  1. POJ 3660 Cow Contest【传递闭包】

    解题思路:给出n头牛,和这n头牛之间的m场比赛结果,问最后能知道多少头牛的排名. 首先考虑排名怎么想,如果知道一头牛打败了a头牛,以及b头牛打赢了这头牛,那么当且仅当a+b+1=n时可以知道排名,即为 ...

  2. shell-1.shell概述、2.shell脚本执行方式

    目录

  3. 紫书 例题8-12 UVa 12627 (找规律 + 递归)

    紫书上有很明显的笔误, 公式写错了.g(k, i)的那个公式应该加上c(k-1)而不是c(k).如果加上c(k-1)那就是这一次 所有的红气球的数目, 肯定大于最下面i行的红气球数 我用的是f的公式, ...

  4. 现代C++

    C++ 是世界上最常用的编程语言之一. 编写良好的 C++ 程序是快速.高效的. 该语言比其他语言更加灵活,因为你可以使用它来创建各种应用,包括有趣刺激的游戏.高性能科学软件.设备驱动程序.嵌入式程序 ...

  5. windos环境python3.5安装 paramiko

    一.执行命令pip install paramiko,情况如下: C:\Users\ZFH>pip install paramikoCollecting paramiko  Downloadin ...

  6. [React] Optimistic UI update in React using setState()

    In this lesson we will refactor an existing UI update from a typical loading approach to an optimist ...

  7. C++primer书店程序

    #include <iostream> #include <string> #include <cassert> #include <algorithm> ...

  8. hadoop学习;datajoin;chain签名;combine()

    hadoop有种简化机制来管理job和control的非线性作业之间的依赖.job对象时mapreduce的表现形式.job对象的实例化可通过传递一个jobconf对象到作业的构造函数中来实现. x. ...

  9. 8、java高级面向对象-重载、构造器重载、初始化块、this、super、对象构造和初始化分析、覆盖、toString

    1.方法的重载(overload) 同一个类中同时存在一个以上的同名函数,参数个数或类型不同或顺序不同,称为方法的重载. 和返回值无关! 构造器重载:非默认构造器和默认构造器其实就是方法的重载. 2. ...

  10. 各大CMS系统优缺点(2017)

    各大CMS系统优缺点(2017) 总结 WordPress之前用过,可能需要再完整的用一个才会比较了解. 从2015年各行业建站规模来看,还有一大批人想自己搭建网站,下面为大家盘点一下比较实用CMS系 ...