四大圖片緩存基本信息
Universal ImageLoader 是很早開源的圖片緩存,在早期被很多應(yīng)用使用。
Picasso 是 Square 開源的項目,且他的主導(dǎo)者是 JakeWharton,所以廣為人知。Glide 是 Google 員工的開源項目,被一些 Google App 使用,在去年的 Google I/O 上被推薦,不過目前國內(nèi)資料不多。Fresco 是 Facebook 在今年上半年開源的圖片緩存,主要特點包括:
(1) 兩個內(nèi)存緩存加上 Native 緩存構(gòu)成了三級緩存
(2) 支持流式,可以類似網(wǎng)頁上模糊漸進式顯示圖片
(3) 對多幀動畫圖片支持更好,如 Gif、WebP
鑒于 Fresco 還沒發(fā)布正式的 1.0 版本,同時一直沒太多時間熟悉 Fresco 源碼,后面對比不包括 Fresco,以后有時間再加入對比
二、基本概念
在正式對比前,先了解幾個圖片緩存通用的概念:(1) RequestManager:請求生成和管理模塊
(2) Engine:引擎部分,負(fù)責(zé)創(chuàng)建任務(wù)(獲取數(shù)據(jù)),并調(diào)度執(zhí)行
(3) GetDataInterface:數(shù)據(jù)獲取接口,負(fù)責(zé)從各個數(shù)據(jù)源獲取數(shù)據(jù)。比如 MemoryCache 從內(nèi)存緩存獲取數(shù)據(jù)、DiskCache 從本地緩存獲取數(shù)據(jù),下載器從網(wǎng)絡(luò)獲取數(shù)據(jù)等。
(4) Displayer:資源(圖片)顯示器,用于顯示或操作資源。比如 ImageView,這幾個圖片緩存都不僅僅支持 ImageView,同時支持其他 View 以及虛擬的 Displayer 概念。
(5) Processor 資源(圖片)處理器負(fù)責(zé)處理資源,比如旋轉(zhuǎn)、壓縮、截取等。
以上概念的稱呼在不同圖片緩存中可能不同,比如 Displayer 在 ImageLoader 中叫做 ImageAware,在 Picasso 和 Glide 中叫做 Target。
三、共同優(yōu)點
1. 使用簡單都可以通過一句代碼可實現(xiàn)圖片獲取和顯示。
2. 可配置度高,自適應(yīng)程度高圖片緩存的下載器(重試機制)、解碼器、顯示器、處理器、內(nèi)存緩存、本地緩存、線程池、緩存算法等大都可輕松配置。
自適應(yīng)程度高,根據(jù)系統(tǒng)性能初始化緩存配置、系統(tǒng)信息變更后動態(tài)調(diào)整策略。比如根據(jù) CPU 核數(shù)確定最大并發(fā)數(shù),根據(jù)可用內(nèi)存確定內(nèi)存緩存大小,網(wǎng)絡(luò)狀態(tài)變化時調(diào)整最大并發(fā)數(shù)等。
3. 多級緩存都至少有兩級緩存、提高圖片加載速度。
4. 支持多種數(shù)據(jù)源支持多種數(shù)據(jù)源,網(wǎng)絡(luò)、本地、資源、Assets 等
5. 支持多種 Displayer不僅僅支持 ImageView,同時支持其他 View 以及虛擬的 Displayer 概念。
其他小的共同點包括支持動畫、支持 transform 處理、獲取 EXIF 信息等。
四、ImageLoader 設(shè)計及優(yōu)點
- 總體設(shè)計及流程
上面是 ImageLoader 的總體設(shè)計圖。整個庫分為 ImageLoaderEngine,Cache 及 ImageDownloader,ImageDecoder,BitmapDisplayer,BitmapProcessor 五大模塊,其中 Cache 分為 MemoryCache 和 DiskCache 兩部分。
簡單的講就是 ImageLoader 收到加載及顯示圖片的任務(wù),并將它交給 ImageLoaderEngine,ImageLoaderEngine 分發(fā)任務(wù)到具體線程池去執(zhí)行,任務(wù)通過 Cache 及 ImageDownloader 獲取圖片,中間可能經(jīng)過 BitmapProcessor 和 ImageDecoder 處理,最終轉(zhuǎn)換為Bitmap 交給 BitmapDisplayer 在 ImageAware 中顯示。 - ImageLoader 優(yōu)點
(1) 支持下載進度監(jiān)聽
(2) 可以在 View 滾動中暫停圖片加載通過 PauseOnScrollListener 接口可以在 View 滾動中暫停圖片加載。
(3) 默認(rèn)實現(xiàn)多種內(nèi)存緩存算法 這幾個圖片緩存都可以配置緩存算法,不過 ImageLoader 默認(rèn)實現(xiàn)了較多緩存算法,如 Size 最大先刪除、使用最少先刪除、最近最少使用、先進先刪除、時間最長先刪除等。
(4) 支持本地緩存文件名規(guī)則定義
五、Picasso 設(shè)計及優(yōu)點
- 總體設(shè)計及流程
上面是 Picasso 的總體設(shè)計圖。整個庫分為 Dispatcher,RequestHandler 及 Downloader,PicassoDrawable 等模塊。
Dispatcher 負(fù)責(zé)分發(fā)和處理 Action,包括提交、暫停、繼續(xù)、取消、網(wǎng)絡(luò)狀態(tài)變化、重試等等。
簡單的講就是 Picasso 收到加載及顯示圖片的任務(wù),創(chuàng)建 Request 并將它交給 Dispatcher,Dispatcher 分發(fā)任務(wù)到具體 RequestHandler,任務(wù)通過 MemoryCache 及 Handler(數(shù)據(jù)獲取接口) 獲取圖片,圖片獲取成功后通過 PicassoDrawable 顯示到 Target 中。
需要注意的是上面 Data 的 File system 部分,Picasso 沒有自定義本地緩存的接口,默認(rèn)使用 http 的本地緩存,API 9 以上使用 okhttp,以下使用 Urlconnection,所以如果需要自定義本地緩存就需要重定義 Downloader。 - Picasso 優(yōu)點
(1) 自帶統(tǒng)計監(jiān)控功能支持圖片緩存使用的監(jiān)控,包括緩存命中率、已使用內(nèi)存大小、節(jié)省的流量等。
(2) 支持優(yōu)先級處理每次任務(wù)調(diào)度前會選擇優(yōu)先級高的任務(wù),比如 App 頁面中 Banner 的優(yōu)先級高于 Icon 時就很適用。
(3) 支持延遲到圖片尺寸計算完成加載
(4) 支持飛行模式、并發(fā)線程數(shù)根據(jù)網(wǎng)絡(luò)類型而變手機切換到飛行模式或網(wǎng)絡(luò)類型變換時會自動調(diào)整線程池最大并發(fā)數(shù),比如 wifi 最大并發(fā)為 4, 4g 為 3,3g 為 2。這里 Picasso 根據(jù)網(wǎng)絡(luò)類型來決定最大并發(fā)數(shù),而不是 CPU 核數(shù)。
(5) “無”本地緩存無”本地緩存,不是說沒有本地緩存,而是 Picasso 自己沒有實現(xiàn),交給了 Square 的另外一個網(wǎng)絡(luò)庫 okhttp 去實現(xiàn),這樣的好處是可以通過請求 Response Header 中的 Cache-Control 及 Expired 控制圖片的過期時間。
六、Glide 設(shè)計及優(yōu)點
- 總體設(shè)計及流程
上面是 Glide 的總體設(shè)計圖。整個庫分為 RequestManager(請求管理器),Engine(數(shù)據(jù)獲取引擎)、 Fetcher(數(shù)據(jù)獲取器)、MemoryCache(內(nèi)存緩存)、DiskLRUCache、Transformation(圖片處理)、Encoder(本地緩存存儲)、Registry(圖片類型及解析器配置)、Target(目標(biāo)) 等模塊。
簡單的講就是 Glide 收到加載及顯示資源的任務(wù),創(chuàng)建 Request 并將它交給RequestManager,Request 啟動 Engine 去數(shù)據(jù)源獲取資源(通過 Fetcher ),獲取到后 Transformation 處理后交給 Target。
Glide 依賴于 DiskLRUCache、GifDecoder 等開源庫去完成本地緩存和 Gif 圖片解碼工作。 - Glide 優(yōu)點
(1) 圖片緩存->媒體緩存Glide 不僅是一個圖片緩存,它支持 Gif、WebP、縮略圖。甚至是 Video,所以更該當(dāng)做一個媒體緩存。
(2) 支持優(yōu)先級處理
(3) 與 Activity/Fragment 生命周期一致,支持 trimMemoryGlide 對每個 context 都保持一個 RequestManager,通過 FragmentTransaction 保持與 Activity/Fragment 生命周期一致,并且有對應(yīng)的 trimMemory 接口實現(xiàn)可供調(diào)用。
(4) 支持 okhttp、VolleyGlide 默認(rèn)通過 UrlConnection 獲取數(shù)據(jù),可以配合 okhttp 或是 Volley 使用。實際 ImageLoader、Picasso 也都支持 okhttp、Volley。
(5) 內(nèi)存友好
① Glide 的內(nèi)存緩存有個 active 的設(shè)計從內(nèi)存緩存中取數(shù)據(jù)時,不像一般的實現(xiàn)用 get,而是用 remove,再將這個緩存數(shù)據(jù)放到一個 value 為軟引用的 activeResources map 中,并計數(shù)引用數(shù),在圖片加載完成后進行判斷,如果引用計數(shù)為空則回收掉。
② 內(nèi)存緩存更小圖片Glide 以 url、view_width、view_height、屏幕的分辨率等做為聯(lián)合 key,將處理后的圖片緩存在內(nèi)存緩存中,而不是原始圖片以節(jié)省大小
③ 與 Activity/Fragment 生命周期一致,支持 trimMemory
④ 圖片默認(rèn)使用默認(rèn) RGB_565 而不是 ARGB_888雖然清晰度差些,但圖片更小,也可配置到 ARGB_888。
其他:Glide 可以通過 signature 或不使用本地緩存支持 url 過期
七、匯總
三者總體上來說,ImageLoader 的功能以及代理容易理解長度都一般。
Picasso 代碼雖然只在一個包下,沒有嚴(yán)格的包區(qū)分,但代碼簡單、邏輯清晰,一兩個小時就能叫深入的了解完。
Glide 功能強大,但代碼量大、流轉(zhuǎn)復(fù)雜。在較深掌握的情況下才推薦使用,免得出了問題難以下手解決。