从设计到实现,一步步教你实现Android-Universal-ImageLoader-辅助类
通過前面幾篇博文。我們分析了 AUI 的緩存、工具類、顯示與載入這幾個方面的代碼。今天呢,我們繼續(xù)研究 AUI 的源代碼,學(xué)習(xí)當(dāng)中的核心輔助工具類。
希望大家能在里面學(xué)到東西哈。
Download
要下載一張圖片,我們想象須要什么哈:首先我們得設(shè)定支持的協(xié)議。得有下載的鏈接。由對應(yīng)的下載鏈接去下載圖片。進(jìn)而得到圖片的輸入流,剩下的就交給圖片的顯示/載入類處理啦。
那么我們能夠設(shè)計出以下的接口:
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());}}
} 看到這里大家可能會疑惑了,我們不是設(shè)計接口么,為啥要搞個枚舉類型,并且還在里面搞那么多亂七八糟的東西……事實上。假設(shè)大家有看過《Thinking In Java》的話就會知道。在 Java 中,enum 實際上就是一個類。由于 enum 定義后的枚舉類在編譯時默認(rèn)繼承 java.lang.Enum 類。而該枚舉類會自己主動被加上 final 關(guān)鍵字修飾。這也使得枚舉類無法被繼承。更詳細(xì)的解釋大家能夠自行 Google 哈。
那么為什么要在 ImageDownloader 里引入這個枚舉類呢?我們最好還是先看看枚舉類內(nèi)究竟有什么。在枚舉類 Scheme 中,主要有四個方法,而這四個方法都用于處理 Uri,如:裁減 Uri、加入 Uri 前綴、推斷 Uri。也就是說,Scheme 的抽象職責(zé)是:對 Uri 進(jìn)行修飾。
而 Scheme 對 Uri 的修飾結(jié)果將交給 ImageDownloader 完畢下載操作。
換言之,Scheme 的抽象與 ImageDownloader 的抽象實際上是不一致的(ImageDownloader 的抽象是下載圖片,而下載圖片所需的 Uri 須要進(jìn)行什么處理才干被 ImageDownloader 使用,并完畢下載事實上不重要),為了讓減少類的耦合度,我們在 ImageDownloader 的內(nèi)部實現(xiàn)了 Scheme 類。
那么有人可能會問了,那我們另外創(chuàng)建一個類不行么?就我的理解來看,肯定是能夠的。由于 Scheme 本質(zhì)上也是一個類,我們新創(chuàng)建一個類。聲明為 final 類。加入對應(yīng)的靜態(tài)常量、方法。事實上效果也是一樣的。
那作者為什么要這么干呢?看過《Effective Java》的朋友可能會知道,實現(xiàn)單例的最佳方法就是使用 enum,詳細(xì)的解釋大家自己去查吧。我就不在這里多說了。
那么作者在這里實際上就是在接口內(nèi)部定義了一個單例。
What is an efficient way to implement a singleton pattern in Java?
BaseImageDownloader 實現(xiàn)了 ImageDownloader 接口,并且依據(jù)我們的需求實現(xiàn)了對應(yīng)的圖片下載細(xì)節(jié),詳細(xì)沒什么好解說的,大家能夠自行閱讀源代碼哈~
Listener
在 AUI 中,實際上須要用到的 Listener 并不多,畢竟圖片載入僅僅是一個非常小的功能模塊嘛。那么 AUI 究竟包括了什么 Listener 呢?
- 圖片載入監(jiān)聽器:監(jiān)聽圖片載入的開始、結(jié)束、失敗、取消
- 圖片載入進(jìn)度監(jiān)聽器:監(jiān)聽圖片載入的進(jìn)度
- 圖片載入滾動監(jiān)聽器:當(dāng)圖片載入正在進(jìn)行,若發(fā)生滾動,則停止載入,換言之,僅僅載入當(dāng)前屏幕顯示的圖片。圖片滾動過程的圖片則不載入。
可能有人會認(rèn)為非常奇怪。為什么圖片載入監(jiān)聽器和圖片載入進(jìn)度監(jiān)聽器要分開實現(xiàn)。事實上我也想不懂。希望有人能給我個解釋……
Assist
在 assist 里面有幾個類我們在之前的博文中已經(jīng)有提過了,我就不再這反復(fù)拉。
比較簡單的類我也會一筆帶過。希望大家理解哈。
deque
在這里面都是一些雙端隊列。比如 LinkedBlockingDeque、LIFOLinkedBlockingDeque。雙端隊列的對應(yīng)知識。以及詳細(xì)實現(xiàn)我相信不用我在這里廢話了,畢竟數(shù)據(jù)結(jié)構(gòu)的課程中一定會說到這個知識點,這也是個主要的、必須掌握的數(shù)據(jù)結(jié)構(gòu)。
那么在這里我們須要了解什么呢?那就是:為什么引入雙端隊列作為 AUI 的數(shù)據(jù)結(jié)構(gòu),雙端隊列較之其它數(shù)據(jù)結(jié)構(gòu)在這個應(yīng)用場景下有什么長處。
我們最好還是先看看 Deque 在哪里被用到吧,在 AUI 庫中搜索發(fā)現(xiàn)。DefaultConfigurationFactory 調(diào)用了 Deque。
那么 DefaultConfigurationFactory 究竟是什么呢?
從該類的命名以及內(nèi)部的方法名我們能夠知道。DefaultConfigurationFactory 就是 AUI 默認(rèn)的配置工廠類,假設(shè)開發(fā)人員沒有自己定義對應(yīng)的配置選項的話,AUI 就會使用這個類所設(shè)置的默認(rèn)選項,完畢對應(yīng)的載入、下載、緩存等等……
最好還是看看以下的代碼段:
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 庫中。雙端隊列這個數(shù)據(jù)結(jié)構(gòu)是用來完畢 AUI 線程處理的。那么為什么要選擇雙端隊列,為什么又選擇 LIFOLinkedBlockingDeque 作為默認(rèn)選項呢?
之所以選擇雙端隊列。是由于 ThreadPoolExecutor 使用的是生產(chǎn)者-消費者模式,在 ThreadPoolExecutor 類內(nèi)部使用 BlockingQueue 作為任務(wù)處理隊列能滿足生產(chǎn)者-消費者模式對任務(wù)存儲數(shù)據(jù)結(jié)構(gòu)的要求。而在我們的 assist 中。LIFOLinkedBlockingDeque 是 LinkedBlockingDeque 的子類。而 LinkedBlockingDeque 實現(xiàn)了 BlockingDeque 接口,BlockingDeque 接口又繼承于 BlockingQueue。
Others
在 assist 中剩下的輔助類我認(rèn)為都挺簡單的,都是一些基本 API 調(diào)用的簡化。大家自己看看源代碼都能看懂的~
轉(zhuǎn)載于:https://www.cnblogs.com/brucemengbm/p/7029281.html
總結(jié)
以上是生活随笔為你收集整理的从设计到实现,一步步教你实现Android-Universal-ImageLoader-辅助类的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 饴字开头的成语有哪些啊?
- 下一篇: 服务注册发现consul之四: 分布式锁