通过前面几篇博文。我们分析了 AUI 的缓存、工具类、显示与载入这几个方面的代码。今天呢,我们继续研究 AUI 的源代码,学习当中的核心辅助工具类。

希望大家能在里面学到东西哈。

Download

要下载一张图片,我们想象须要什么哈:首先我们得设定支持的协议。得有下载的链接。由对应的下载链接去下载图片。进而得到图片的输入流,剩下的就交给图片的显示/载入类处理啦。

那么我们能够设计出以下的接口:

public interface ImageDownloader {

    InputStream getStream(String imageUri, Object extra) throws IOException;

    public enum Scheme {
HTTP("http"), HTTPS("https"), FILE("file"), CONTENT("content"), ASSETS("assets"), DRAWABLE("drawable"), UNKNOWN(""); private String scheme;
private String uriPrefix; Scheme(String scheme) {
this.scheme = scheme;
uriPrefix = scheme + "://";
} public static Scheme ofUri(String uri) {
if (uri != null) {
for (Scheme s : values()) {
if (s.belongsTo(uri)) {
return s;
}
}
}
return UNKNOWN;
} private boolean belongsTo(String uri) {
return uri.toLowerCase(Locale.US).startsWith(uriPrefix);
} public String wrap(String path) {
return uriPrefix + path;
} public String crop(String uri) {
if (!belongsTo(uri)) {
throw new IllegalArgumentException(String.format("URI [%1$s] doesn't have expected scheme [%2$s]", uri, scheme));
}
return uri.substring(uriPrefix.length());
}
}
}

看到这里大家可能会疑惑了,我们不是设计接口么,为啥要搞个枚举类型,并且还在里面搞那么多乱七八糟的东西……事实上。假设大家有看过《Thinking In Java》的话就会知道。在 Java 中,enum 实际上就是一个类。由于 enum 定义后的枚举类在编译时默认继承 java.lang.Enum 类。而该枚举类会自己主动被加上 final 关键字修饰。这也使得枚举类无法被继承。更详细的解释大家能够自行 Google 哈。

那么为什么要在 ImageDownloader 里引入这个枚举类呢?我们最好还是先看看枚举类内究竟有什么。在枚举类 Scheme 中,主要有四个方法,而这四个方法都用于处理 Uri,如:裁减 Uri、加入 Uri 前缀、推断 Uri。也就是说,Scheme 的抽象职责是:对 Uri 进行修饰。

而 Scheme 对 Uri 的修饰结果将交给 ImageDownloader 完毕下载操作。

换言之,Scheme 的抽象与 ImageDownloader 的抽象实际上是不一致的(ImageDownloader 的抽象是下载图片,而下载图片所需的 Uri 须要进行什么处理才干被 ImageDownloader 使用,并完毕下载事实上不重要),为了让减少类的耦合度,我们在 ImageDownloader 的内部实现了 Scheme 类。

那么有人可能会问了,那我们另外创建一个类不行么?就我的理解来看,肯定是能够的。由于 Scheme 本质上也是一个类,我们新创建一个类。声明为 final 类。加入对应的静态常量、方法。事实上效果也是一样的。

那作者为什么要这么干呢?看过《Effective Java》的朋友可能会知道,实现单例的最佳方法就是使用 enum,详细的解释大家自己去查吧。我就不在这里多说了。

那么作者在这里实际上就是在接口内部定义了一个单例。

What is an efficient way to implement a singleton pattern in Java?

BaseImageDownloader 实现了 ImageDownloader 接口,并且依据我们的需求实现了对应的图片下载细节,详细没什么好解说的,大家能够自行阅读源代码哈~

Listener

在 AUI 中,实际上须要用到的 Listener 并不多,毕竟图片载入仅仅是一个非常小的功能模块嘛。那么 AUI 究竟包括了什么 Listener 呢?

  • 图片载入监听器:监听图片载入的開始、结束、失败、取消
  • 图片载入进度监听器:监听图片载入的进度
  • 图片载入滚动监听器:当图片载入正在进行,若发生滚动,则停止载入,换言之,仅仅载入当前屏幕显示的图片。图片滚动过程的图片则不载入。

可能有人会认为非常奇怪。为什么图片载入监听器和图片载入进度监听器要分开实现。事实上我也想不懂。希望有人能给我个解释……

Assist

在 assist 里面有几个类我们在之前的博文中已经有提过了,我就不再这反复拉。

比較简单的类我也会一笔带过。希望大家理解哈。

deque

在这里面都是一些双端队列。比如 LinkedBlockingDeque、LIFOLinkedBlockingDeque。双端队列的对应知识。以及详细实现我相信不用我在这里废话了,毕竟数据结构的课程中一定会说到这个知识点,这也是个主要的、必须掌握的数据结构。

那么在这里我们须要了解什么呢?那就是:为什么引入双端队列作为 AUI 的数据结构,双端队列较之其它数据结构在这个应用场景下有什么长处。

我们最好还是先看看 Deque 在哪里被用到吧,在 AUI 库中搜索发现。DefaultConfigurationFactory 调用了 Deque。

那么 DefaultConfigurationFactory 究竟是什么呢?

从该类的命名以及内部的方法名我们能够知道。DefaultConfigurationFactory 就是 AUI 默认的配置工厂类,假设开发人员没有自己定义对应的配置选项的话,AUI 就会使用这个类所设置的默认选项,完毕对应的载入、下载、缓存等等……

最好还是看看以下的代码段:

    public static Executor createExecutor(int threadPoolSize, int threadPriority,
QueueProcessingType tasksProcessingType) {
boolean lifo = tasksProcessingType == QueueProcessingType.LIFO;
BlockingQueue<Runnable> taskQueue =
lifo ? new LIFOLinkedBlockingDeque<Runnable>() : new LinkedBlockingQueue<Runnable>();
return new ThreadPoolExecutor(threadPoolSize, threadPoolSize, 0L, TimeUnit.MILLISECONDS, taskQueue,
createThreadFactory(threadPriority, "uil-pool-"));
}

在这段代码中。我们会获得线程池,并且用 LIFOLinkedBlockingDeque 作为线程的处理队列。也就是说,在 AUI 库中。双端队列这个数据结构是用来完毕 AUI 线程处理的。那么为什么要选择双端队列,为什么又选择 LIFOLinkedBlockingDeque 作为默认选项呢?

之所以选择双端队列。是由于 ThreadPoolExecutor 使用的是生产者-消费者模式,在 ThreadPoolExecutor 类内部使用 BlockingQueue 作为任务处理队列能满足生产者-消费者模式对任务存储数据结构的要求。而在我们的 assist 中。LIFOLinkedBlockingDeque 是 LinkedBlockingDeque 的子类。而 LinkedBlockingDeque 实现了 BlockingDeque 接口,BlockingDeque 接口又继承于 BlockingQueue。

Others

在 assist 中剩下的辅助类我认为都挺简单的,都是一些基本 API 调用的简化。大家自己看看源代码都能看懂的~

从设计到实现,一步步教你实现Android-Universal-ImageLoader-辅助类的更多相关文章

  1. 一步步教你轻松学关联规则Apriori算法

    一步步教你轻松学关联规则Apriori算法 (白宁超 2018年10月22日09:51:05) 摘要:先验算法(Apriori Algorithm)是关联规则学习的经典算法之一,常常应用在商业等诸多领 ...

  2. 一步步教你搭建VS环境下用C#写WebDriver脚本

    一步步教你搭建VS环境下用C#写WebDriver脚本http://www.automationqa.com/forum.php?mod=viewthread&tid=3529&fro ...

  3. 我写了个教程《一步步教你把ubuntu安装到U盘》

    一步步教你把ubuntu安装到U盘 作者 Val 2452013147@qq.com 原因: 由于某些原因(学生党),需要把ubuntu安装到U盘到处走,百度了一下,教程都不是很好,要么很复杂,要么不 ...

  4. 一步步教你读懂NET中IL(附带图)

    一步步教你读懂NET中IL(附带图) 接触NET也有1年左右的时间了,NET的内部实现对我产生了很大的吸引力,在msdn上找到一篇关于NET的IL代码的图解说明,写的挺不错的.个人觉得:能对这些底部的 ...

  5. 一步步教你轻松学奇异值分解SVD降维算法

    一步步教你轻松学奇异值分解SVD降维算法 (白宁超 2018年10月24日09:04:56 ) 摘要:奇异值分解(singular value decomposition)是线性代数中一种重要的矩阵分 ...

  6. 一步步教你轻松学支持向量机SVM算法之案例篇2

    一步步教你轻松学支持向量机SVM算法之案例篇2 (白宁超 2018年10月22日10:09:07) 摘要:支持向量机即SVM(Support Vector Machine) ,是一种监督学习算法,属于 ...

  7. 一步步教你轻松学支持向量机SVM算法之理论篇1

    一步步教你轻松学支持向量机SVM算法之理论篇1 (白宁超 2018年10月22日10:03:35) 摘要:支持向量机即SVM(Support Vector Machine) ,是一种监督学习算法,属于 ...

  8. 一步步教你轻松学主成分分析PCA降维算法

    一步步教你轻松学主成分分析PCA降维算法 (白宁超 2018年10月22日10:14:18) 摘要:主成分分析(英语:Principal components analysis,PCA)是一种分析.简 ...

  9. 一步步教你轻松学K-means聚类算法

    一步步教你轻松学K-means聚类算法(白宁超  2018年9月13日09:10:33) 导读:k-均值算法(英文:k-means clustering),属于比较常用的算法之一,文本首先介绍聚类的理 ...

  10. 一步步教你轻松学朴素贝叶斯模型算法Sklearn深度篇3

    一步步教你轻松学朴素贝叶斯深度篇3(白宁超   2018年9月4日14:18:14) 导读:朴素贝叶斯模型是机器学习常用的模型算法之一,其在文本分类方面简单易行,且取得不错的分类效果.所以很受欢迎,对 ...

随机推荐

  1. 小贝_redis list类型学习

    redis  list类型 一.查看list类型的命令 二.list命令具体解释 一.查看list类型的命令 1.在终端数据 help @list 127.0.0.1:6379>help @li ...

  2. Android之输入内容监听回车键【Editor】

    2.输入内容时按下回车键时监听 username.setOnEditorActionListener(new OnEditorActionListener() { @Override public b ...

  3. python 同步IO

    IO在计算机中指Input/Output 由CPU这个超快的计算核心来执行,涉及到数据交换的地方,通常是磁盘.网络等,就需要IO接口.IO编程中,Stream(流)是一个很重要的概念,可以把流想象成一 ...

  4. 关于nth-of-type和nth-child的关系

    一开始写样式的时候喜欢全部元素都来个class,后面发现这样一个页面下来很多个class,起名字起到发慌,然后老师说该多用 逻辑关系来写样式,就是这种第几个孩子啊这种,不知道你们有没有这种烦恼,要用的 ...

  5. SecondaryNameNode合并元信息过程

  6. java9新特性-8-语法改进:钻石操作符(Diamond Operator)使用升级

    1.使用说明 我们将能够与匿名实现类共同使用钻石操作符(diamond operator) 在java8中如下的操作是会报错的:   编译报错信息:'<>' cannot be used ...

  7. BZOJ 1174: [Balkan2007]Toponyms

    Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 735  Solved: 102[Submit][Status][Discuss] Descriptio ...

  8. CentOS6.8下完全干净卸载mysql

    来源整理于 https://www.cnblogs.com/wanghuaijun/p/6398240.html 虚拟机CentOS6.8下 先执行命令查看目录是否存在mysql 文件夹:  cd  ...

  9. 《剑指offer》数值的整数次方

    一.题目描述 给定一个double类型的浮点数base和int类型的整数exponent.求base的exponent次方. 二.输入 double base, int exponent 三.输出 b ...

  10. AIX系统谨慎使用reboot命令

    在客户一次停机维护中,发现了这个问题. 环境是ORACLE 10G RAC for AIX6,使用了HACMP管理共享磁盘. 在停机维护时间段内需要重启主机,当关闭了数据库和CLUSTER后,节点1使 ...