摘要:這是快的打車移動端架構師、Android 開源項目源碼解析codeKK發起人 吳更新(@Trinea)在MDCC上分享的內容,從整體設計和原理上對幾個圖片緩存進行對比,沒用到它們的朋友也能夠了解它們在某些特性上的實現。算法
【CSDN現場報道】10月14日-16日,「 2015移動開發者大會 · 中國」(Mobile Developer Conference China 2015,簡稱MDCC 2015)在北京新雲南皇冠假日酒店隆重舉行。本次大會由全球最大中文IT社區CSDN和中國最具關注度的全方位創業平臺創新工場聯合主辦,以「萬物互聯,移動爲先」爲主題,邀請國內外業界領袖與技術專家共論移動開發的熱點,在實踐中剖析技術方案與趨勢。緩存
快的打車移動端架構師 吳更新(Trinea) 網絡
這是快的打車移動端架構師、Android 開源項目源碼解析 codeKK 發起人 吳更新( @Trinea)在MDCC上分享的內容(略微改動),也是源碼解析第一期發佈時介紹的源碼解析後續會慢慢作的事。從整體設計和原理上對幾個圖片緩存進行對比,沒用到它們的朋友也能夠了解它們在某些特性上的實現。(PPT下載地址>>Android開源項目選型之圖片緩存)架構
上篇關於選擇開源項目的好處及如何選擇開源項目可見: 開源項目使用及選型。併發
Universal ImageLoader 是很早開源的圖片緩存,在早期被不少應用使用。ide
Picasso 是 Square 開源的項目,且他的主導者是 JakeWharton,因此廣爲人知。性能
Glide 是 Google 員工的開源項目,被一些 Google App 使用,在去年的 Google I/O 上被推薦,不過目前國內資料很少。動畫
Fresco 是 Facebook 在今年上半年開源的圖片緩存,主要特色包括:url
鑑於 Fresco 還沒發佈正式的 1.0 版本,同時一直沒太多時間熟悉 Fresco 源碼,後面對比不包括 Fresco,之後有時間再加入對比。spa
在正式對比前,先了解幾個圖片緩存通用的概念:
以上概念的稱呼在不一樣圖片緩存中可能不一樣,好比 Displayer 在 ImageLoader 中叫作 ImageAware,在 Picasso 和 Glide 中叫作 Target。
1. 使用簡單
均可以經過一句代碼可實現圖片獲取和顯示。
2. 可配置度高,自適應程度高
圖片緩存的下載器(重試機制)、解碼器、顯示器、處理器、內存緩存、本地緩存、線程池、緩存算法等大均可輕鬆配置。
自適應程度高,根據系統性能初始化緩存配置、系統信息變動後動態調整策略。
好比根據 CPU 核數肯定最大併發數,根據可用內存肯定內存緩存大小,網絡狀態變化時調整最大併發數等。
3. 多級緩存
都至少有兩級緩存、提升圖片加載速度。
4. 支持多種數據源
支持多種數據源,網絡、本地、資源、Assets 等
5. 支持多種 Displayer
不只僅支持 ImageView,同時支持其餘 View 以及虛擬的 Displayer 概念。
其餘小的共同點包括支持動畫、支持 transform 處理、獲取 EXIF 信息等。
上面是 ImageLoader 的整體設計圖。整個庫分爲 ImageLoaderEngine,Cache 及 ImageDownloader,ImageDecoder,BitmapDisplayer,BitmapProcessor 五大模塊,其中 Cache 分爲 MemoryCache 和 DiskCache 兩部分。
簡單的講就是 ImageLoader 收到加載及顯示圖片的任務,並將它交給 ImageLoaderEngine,ImageLoaderEngine 分發任務到具體線程池去執行,任務經過 Cache 及 ImageDownloader 獲取圖片,中間可能通過 BitmapProcessor 和 ImageDecoder 處理,最終轉換爲Bitmap 交給 BitmapDisplayer 在 ImageAware 中顯示。
(1) 支持下載進度監聽
(2) 能夠在 View 滾動中暫停圖片加載
經過 PauseOnScrollListener 接口能夠在 View 滾動中暫停圖片加載。
(3) 默認實現多種內存緩存算法 這幾個圖片緩存均可以配置緩存算法,不過 ImageLoader 默認實現了較多緩存算法,如 Size 最大先刪除、使用最少先刪除、最近最少使用、先進先刪除、時間最長先刪除等。
(4) 支持本地緩存文件名規則定義
上面是 Picasso 的整體設計圖。整個庫分爲 Dispatcher,RequestHandler 及 Downloader,PicassoDrawable 等模塊。
Dispatcher 負責分發和處理 Action,包括提交、暫停、繼續、取消、網絡狀態變化、重試等等。
簡單的講就是 Picasso 收到加載及顯示圖片的任務,建立 Request 並將它交給 Dispatcher,Dispatcher 分發任務到具體 RequestHandler,任務經過 MemoryCache 及 Handler(數據獲取接口) 獲取圖片,圖片獲取成功後經過 PicassoDrawable 顯示到 Target 中。
須要注意的是上面 Data 的 File system 部分,Picasso 沒有自定義本地緩存的接口,默認使用 http 的本地緩存,API 9 以上使用 okhttp,如下使用 Urlconnection,因此若是須要自定義本地緩存就須要重定義 Downloader。
(1) 自帶統計監控功能
支持圖片緩存使用的監控,包括緩存命中率、已使用內存大小、節省的流量等。
(2) 支持優先級處理
每次任務調度前會選擇優先級高的任務,好比 App 頁面中 Banner 的優先級高於 Icon 時就很適用。
(3) 支持延遲到圖片尺寸計算完成加載
(4) 支持飛行模式、併發線程數根據網絡類型而變
手機切換到飛行模式或網絡類型變換時會自動調整線程池最大併發數,好比 wifi 最大併發爲 4, 4g 爲 3,3g 爲 2。
這裏 Picasso 根據網絡類型來決定最大併發數,而不是 CPU 核數。
(5) 「無」本地緩存
無」本地緩存,不是說沒有本地緩存,而是 Picasso 本身沒有實現,交給了 Square 的另一個網絡庫 okhttp 去實現,這樣的好處是能夠經過請求 Response Header 中的 Cache-Control 及 Expired 控制圖片的過時時間。
上面是 Glide 的整體設計圖。整個庫分爲 RequestManager(請求管理器),Engine(數據獲取引擎)、Fetcher(數據獲取器)、MemoryCache(內存緩存)、DiskLRUCache、Transformation(圖片處理)、Encoder(本地緩存存儲)、Registry(圖片類型及解析器配置)、Target(目標)等模塊。
簡單的講就是 Glide 收到加載及顯示資源的任務,建立 Request 並將它交給RequestManager,Request 啓動 Engine 去數據源獲取資源(經過 Fetcher ),獲取到後 Transformation 處理後交給 Target。
Glide 依賴於 DiskLRUCache、GifDecoder 等開源庫去完成本地緩存和 Gif 圖片解碼工做。
(1) 圖片緩存->媒體緩存
Glide 不只是一個圖片緩存,它支持 Gif、WebP、縮略圖。甚至是 Video,因此更該當作一個媒體緩存。
(2) 支持優先級處理
(3) 與 Activity/Fragment 生命週期一致,支持 trimMemory
Glide 對每一個 context 都保持一個 RequestManager,經過 FragmentTransaction 保持與 Activity/Fragment 生命週期一致,而且有對應的 trimMemory 接口實現可供調用。
(4) 支持 okhttp、Volley
Glide 默認經過 UrlConnection 獲取數據,能夠配合 okhttp 或是 Volley 使用。實際 ImageLoader、Picasso 也都支持 okhttp、Volley。
(5) 內存友好
① Glide 的內存緩存有個 active 的設計
從內存緩存中取數據時,不像通常的實現用 get,而是用 remove,再將這個緩存數據放到一個 value 爲軟引用的 activeResources map 中,並計數引用數,在圖片加載完成後進行判斷,若是引用計數爲空則回收掉。
② 內存緩存更小圖片
Glide 以 url、viewwidth、viewheight、屏幕的分辨率等作爲聯合 key,將處理後的圖片緩存在內存緩存中,而不是原始圖片以節省大小
③ 與 Activity/Fragment 生命週期一致,支持 trimMemory
④ 圖片默認使用默認 RGB565 而不是 ARGB888
雖然清晰度差些,但圖片更小,也可配置到 ARGB_888。
其餘:Glide 能夠經過 signature 或不使用本地緩存支持 url 過時
三者整體上來講,ImageLoader 的功能以及代理容易理解長度都通常。
Picasso 代碼雖然只在一個包下,沒有嚴格的包區分,但代碼簡單、邏輯清晰,一兩個小時就能叫深刻的瞭解完。
Glide 功能強大,但代碼量大、流轉複雜。在較深掌握的狀況下才推薦使用,省得出了問題難如下手解決。