Glide 系列(一) 圖片載入框架對比
本文主要比對框架包括:Universal Imageloader(下文簡稱 UIL)、Picasso、 Glide、Fresco。先對各個框架做簡單介紹,再對框架進行對比。
簡介篇
UIL
UIL 是一個老牌的圖片載入框架,旨在提供一個強大的、靈活的和高度可定製的工具,以實現影象載入、快取和顯示功能。
UIL 支援多執行緒圖片載入,支援佔位圖和錯誤圖、支援圖片下載進度的監聽,支援快取不同尺寸圖片,支援圖片記憶體快取和硬碟快取,支援自定義圖片載入格式,支援 ListView或者 GridView 滾動時暫停載入。但 UIL 不支援動圖展示,且該框架的作者已經宣佈不在對其進行維護。
ImageLoader.getInstance()
.displayImage("http://inthecheesefactory.com/uploads/source/glidepicasso/cover.jpg" , ivImg, null);
Picasso
Picasso 其名字來源於畫家畢加索,是著名開源公司 Square 的作品,與 OkHttp 和 Retrofit 合稱開發三件套。Picasso 同樣支援佔位圖和錯誤圖展示,支援圖形變換操作,支援記憶體和硬碟快取,支援載入本地或者網路資源,比較有特色的是其擁有統計功能,可以知道一共使用了多少記憶體,快取命中率, 圖片來自記憶體還是硬碟等。Picasso 使用起來也是簡單方便,基本上一行程式碼可解決顯示圖片請求。
Picasso.with(context)
.load("http://inthecheesefactory.com/uploads/source/glidepicasso/cover.jpg" )
.into(ivImg);
Glide
Glide 是一個 Google 官方推薦的快速高效的圖片載入庫,主要目標是讓任何形式的圖片列表的滾動儘可能地變得更快、更平滑。
Glide 提供了簡單易用的API,典型流式語法風格,大部分展示圖片需求可以一行程式碼搞定。Glide 的 API 還特別靈活,在支援開發者自定義配置和模組的同時又和其圖片載入圖片的邏輯沒有任何交集,是一種低耦合的程式設計方式的實現。預設情況下,通訊元件使用 HttpUrlConnection,但也提供了 Volley 和 OkHttp 快速整合的工具。
Glide.with(fragment).load(url).into(imageView);
Glide使用了多個步驟來確保在Android上載入圖片儘可能的快速和平滑:
- 自動、智慧地下采樣(downsampling)和快取(caching),以最小化儲存開銷和解碼次數;
- 積極的資源重用,例如位元組陣列和Bitmap,以最小化昂貴的垃圾回收和堆碎片影響;
- 深度的生命週期整合,以確保僅優先處理活躍的 Fragment 和 Activity 的請求,並有利於應用在必要時釋放資源以避免在後臺時被殺掉。
生命週期的整合也是 Glide 的一大特色。
Fresco
Fresco 是一個強大的圖片載入元件,其設計中有一個叫做 Image Pipeline 的模組,負責從網路、本地檔案系統、本地資源載入圖片。為了最大限度節省空間和CPU時間,它含有 3 級快取設計(2級記憶體,1級磁碟)。還有一個叫做 Drawees 的模組,它會在圖片載入完成前顯示佔位圖,載入成功後自動替換為目標圖片。當圖片不再顯示在螢幕上時,它會及時地釋放記憶體和空間佔用。
Fresco 包含以下特性:
- 記憶體管理:在 Andrid 5.0 以下系統,Fresco 會將圖片放到 ASM(Anonymous Shared Memory,匿名共享記憶體)區域,減少了低效能手機上 OOM 的發生。在圖片不用時,應該顯式釋放這部分資源,SimpleDraweeView 自動處理了這個釋放過程。在 5.0 及以上版本系統,由於 Android 對其記憶體管理做了很大優化,Bitmap 快取位於 Java 堆區,同樣避免了 OOM 的發生。
- 圖片載入:Image Pipeline 允許你用多種方式來定義圖片的載入過程圖片可以來自遠端伺服器,本地檔案,或者Content Provider,本地資源。壓縮後的檔案快取在本地儲存中,Bitmap資料快取在記憶體中。
- 圖片繪製:可自定義佔點陣圖或者進度條,自定義 overlay,現在失敗後的點選重試等。
- 圖片漸進式呈現:Android 本身的圖片庫不支援此格式,但是Fresco支援漸進式圖片。漸進式格式先呈現大致的圖片輪廓,然後隨著圖片下載的繼續,呈現逐漸清晰的圖片,對於移動裝置,尤其是慢網路有極大的利好,可帶來更好的使用者體驗。
- 友好的支援 Gif 圖片和 Webp 動圖。
Fresco 使用時需要用其框架定義的元件,且明確指定尺寸 或者用 match_parent 標註。
<com.facebook.drawee.view.SimpleDraweeView
android:id="@+id/my_image_view"
android:layout_width="130dp"
android:layout_height="130dp"
fresco:placeholderImage="@drawable/my_drawable"
/>
Uri uri = Uri.parse("https://raw.githubusercontent.com/facebook/fresco/gh-pages/static/logo.png");
SimpleDraweeView draweeView = (SimpleDraweeView) findViewById(R.id.my_image_view);
draweeView.setImageURI(uri);
對比篇
共同特性
- 支援佔位圖或者載入錯誤圖
- 支援 影象變換,如 裁剪、尺寸修改、方圓轉換等
- 可配置度高,圖片快取的記憶體快取、本地快取、執行緒池、快取演算法等大都可輕鬆配置。
- 自適應程度高,根據系統性能初始化快取配置、系統資訊變更後動態調整策略。比如根據 CPU 核數確定最大併發數,根據可用記憶體確定記憶體快取大小,網路狀態變化時調整最大併發數等。
- 多級快取,都至少有二級快取,提高圖片的載入速度
- 支援多種資料來源,如網路、本地、Assets等
- 支援多種 Displayer,支援自定義的 Displayer 概念。
- 支援配置圖片格式,如配置 ARGB_8888、RGB_565 等
對比表格
對比圖.png磁碟快取
我們先囉嗦兩句,來看一下儲存器的層次結構,簡單分為:暫存器、快取記憶體、主存、本地磁碟。
儲存器層次模型.jpg
此圖由上到下資料訪問速度在逐層降低,從記憶體讀取資料的速度遠遠大於從硬碟讀取資料,從硬碟讀取資料的速度遠遠大於從網路訪問資料的速度,且網路訪問還有可能失敗。暫存器、快取記憶體這兩層對於我們 app 開發者來說是透明的,無需考慮,我們只需將記憶體快取和硬碟快取利用起來就可以了。基本上所有的圖片載入框架都是在記憶體和硬碟這兩個層次上做的資料快取。記憶體快取作為第一級快取,可以避免將同一張圖片重複載入到記憶體;硬碟快取作為第二級快取,可以避免重複下載同一張網路圖片。
我們知道 ImageView 在顯示圖片時只是起一個容器的作用,裡面放置的圖片是 一個由畫素組成的二維矩陣。既然是一個容器,那圖片大小可能大於容器,也可能小於容器,所以才有了 ImageView 的 scaleType 屬性。當圖片大於容器時,可以將圖片壓縮,裁剪;當圖片小於容器時既可以放大填充容器,也可以不做任何事情。且圖片在硬碟中的大小並不等於在記憶體中的大小。圖片在記憶體中的大小取決於其編碼格式。許多圖片載入框架會根據 ImageView 大小對圖片做縮略處理,這樣既保證了清晰度又減少了記憶體耗用。
全尺寸 指 url 對應的圖片,實際尺寸為 ImageView 尺寸相同的圖片。對於 Picasso,不管 ImageView 如何變換大小,只會快取一個全尺寸的圖片。對於 Glide、UIL、Fresco 都支援快取同一圖片的不同尺寸。對同一張圖片快取不同尺寸意味著需要更大的快取空間,但同時也能提供了更快的展示速度,此處就是用空間換取時間,省去了每次顯示之前將圖片重新調整大小的時間。所以快取多尺寸的圖片框架會相較於快取原始尺寸的更加快,但由於佔據了更多的空間,這一點可以按需設定。
圖片格式
不論採用哪個框架,同一張圖片其顯示質量取決於圖片在記憶體中的格式,與框架無關。這四個框架都支援配置圖片格式。格式清晰度從高到低如下:
ARGB_8888 >RGB_565 > ARGB_4444 >ALPHA_8
附:在這對圖片格式做一個簡單介紹:其中 A,代表透明度;R,代表 Red, 紅色;G,代表 Green,綠色;B,代表 Blue,藍色。
- ALPHA_8,代表畫素只有透明度資訊,沒有顏色資訊,一個畫素佔 8 bit,即 1 Byte。
- RGB_565,代表畫素只有顏色資訊,沒有透明度資訊,其中 R 佔用 5 bit,G 佔用 6 bit,B 佔用 5 bit,一個畫素大小為 5+6+5=16 bit ,即 2 Byte。
- ARGB_4444,代表畫素既有透明度資訊,也有顏色資訊,其中 A 佔用 4 bit,R 佔用 4 bit,G 佔用 4 bit,B 佔用 4 bit,一個畫素大小為 4+4+4+4=16 bit ,即 2 Byte。
- ARGB_8888,代表畫素既有透明度資訊,也有顏色資訊,其中 A 佔用 8 bit,R 佔用 8 bit,G 佔用 8 bit,B 佔用 8 bit,一個畫素大小為 8+8+8+8=32 bit ,即 4 Byte。
這幾個欄位在 Android 原始碼 Bitmap.Config 有中定義,可以看到 ARGB_8888 格式 是佔用空間最大的,一個畫素點要佔用 4 Byte 記憶體,由於儲存了更多的圖片細節資訊,所以此格式也是顯示圖片最清晰的。ARGB_4444 和 RGB_565 佔用記憶體為 ARGB_8888 的一半。ARGB_4444 雖然設計理念是為了保留透明度的同時又節省記憶體,但由於其顯示的影象質量太差而遭到棄用。RGB_565 和 ARGB_8888 是最為通用的兩種圖片格式,可以按需選取。如果必須保留圖片的透明度資訊,則建議使用 ARGB_8888, 如果APP 記憶體吃緊同時對透明度沒有要求的話,可使用 RGB_565。
包體積
UIL 和 Picasso 包體積較小,對安裝包影響不大。
Glide 包體積略大,其功能十分強大,內部實現及其複雜,其方法數較多,使用時可能會遇到 65k 問題。
Fresco 包體積很大,若按照正確步驟使用了 Fresco,引入後釋出包的體積應當不會增加 500Kb。使用者可以根據自己需求有選擇的新增動畫依賴庫和 WebP 支援包,這種模組化機制使得基礎 Fresco 庫很輕,增加一個庫大約包體積會增加 100 KB。
如何選擇圖片載入框架
UIL:建議棄用,除非你的專案一直在用 UIL 且框架遷移成本(時間成本)比較大。否則不建議使用或沿用,因為官方已經不再對其維護,且由於不支援動圖,若 app 有動圖支援的話還需引入其他圖片框架,增加應用體積,還不如一步到位。
Picasso:不建議使用,Glide 是 Picasso 的加強版,可以說它的目的就是為了取代 Picasso,所以在 Glide 和 Picasso 之間選擇,優先推薦 Glide 。
Glide vs Fresco:這兩個框架效能不分伯仲,都可以減少 OOM 的發生。Glide 注重於平滑的滾動,善於處理大型的圖片流,Glide還支援播放短視訊,有此需求的話 Glide 為不二之選,另外 Glide 還有一個隱藏的優點,它是 Google 官方推薦的框架,所以相對於後期維護成本來說更低一些。Fresco 的優點是記憶體管理,尤其是在 5.0 以下的系統中優化做的非常好,將圖片放在 ASM 中。其缺點也很明顯,包的體積太大,其在圖片多的應用中更能體現其價值。Fresco 對程式碼的侵入性可能會更高一些,由於所有的View 元件需要繼承自一個基類 DraweeView ,需指定明確尺寸或者用 match_parent 來佈局(為了更好的使用者體驗,解決佔位圖和真實圖尺寸大小不匹配導致UI跳躍的問題),如果你是一個新專案,可以考慮用 Fresco。
總結:框架只在Glide 和 Fresco 中選擇,Glide 是 Google 官方推薦的框架,是開發者的首選。如果你對包體積沒有要求,且圖片需求特別多的情況推薦使用 Fresco。
附:
http://blog.csdn.net/zivensonice/article/details/51822968
http://www.mamicode.com/info-detail-929571.html
這兩個連結是對各個框架載入圖片時堆記憶體、本地記憶體、載入時間、請求次數的對比,有興趣的可以自己參考下。筆者個人感覺參考性不是很大,在多個機型測試結果不穩定,及同機型上框架切換時資料變化慢。現在 Android Studio 3.0 版本有 Android Profiler,可以點開觀察記憶體情況,這個只支援5.0版本以上的手機哦。