博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
从设计到实现,一步步教你实现Android-Universal-ImageLoader-辅助类
阅读量:4638 次
发布时间:2019-06-09

本文共 4185 字,大约阅读时间需要 13 分钟。

通过前面几篇博文。我们分析了 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,详细的解释大家自己去查吧。我就不在这里多说了。

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

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
taskQueue = lifo ? new LIFOLinkedBlockingDeque
() : new LinkedBlockingQueue
(); 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 调用的简化。大家自己看看源代码都能看懂的~

转载于:https://www.cnblogs.com/brucemengbm/p/7029281.html

你可能感兴趣的文章
smartupload 上传文件时 把页面编码改成gbk 解决乱码
查看>>
EPS是什么格式
查看>>
Python的数据库操作(Sqlalchemy)
查看>>
2.抽取代码(BaseActivity)
查看>>
My simplified pickit2 clone
查看>>
Redis 入门知识
查看>>
夏天过去了, 姥爷推荐几套来自smashingmagzine的超棒秋天主题壁纸
查看>>
转--Android如何在java代码中设置margin
查看>>
反射的所有api
查看>>
Js 判断网页窗口是否滚动到底部
查看>>
上传文件
查看>>
css 定位及遮罩层小技巧
查看>>
用java向mysql数据库中插入数据为空
查看>>
项目中非常有用并且常见的ES6语法
查看>>
dateTimePicker编辑状态下,取值不正确的问题
查看>>
mac 端口转发方案
查看>>
[2017.02.23] Java8 函数式编程
查看>>
loadrunner支持https协议的操作方法-经验总结
查看>>
Knowledge Point 20180305 数据在计算机中的表示
查看>>
谈谈对web标准的理解
查看>>