圖片加載庫原理
爲什麼要使用三級緩存
- 如今的 Android App 經常會需要網絡交互,通過網絡獲取圖片是再正常不過的事了
- 假如每次啓動的時候都從網絡拉取圖片的話,勢必會消耗很多流量。在當前的狀況下,對於非wifi用戶來說,流量還是很貴的,一個很耗流量的應用,其用戶數量級肯定要受到影響
- 特別是,當我們想要重複瀏覽一些圖片時,如果每一次瀏覽都需要通過網絡獲取,流量的浪費可想而知
- 所以提出三級緩存策略,通過網絡、本地、內存三級緩存圖片,來減少不必要的網絡交互,避免浪費流量
什麼是三級緩存
- 網絡緩存, 不優先加載, 速度慢,浪費流量
- 本地緩存, 次優先加載, 速度快
- 內存緩存, 優先加載, 速度最快
三級緩存原理
- 首次加載 Android App 時,肯定要通過網絡交互來獲取圖片,之後我們可以將圖片保存至本地SD卡和內存中
- 之後運行 App 時,優先訪問內存中的圖片緩存,若內存中沒有,則加載本地SD卡中的圖片
- 總之,只在初次訪問新內容時,才通過網絡獲取圖片資源
圖片加載庫簡介
通過對比來介紹三大圖片加載庫(由於ImageLoader已經停止更新,故不做介紹):
名稱 | Picasso | Glide | Fresco |
---|---|---|---|
作者 | Square | Google員工開源項目 |
Picasso
功能和優點
- 支持統計監控功能,包括緩存命中率、已使用內存大小、節省的流量等。
- 支持優先級操作
- 支持延遲到圖片尺寸計算完成加載
- 根據網絡狀態自動切換併發線程數量,包括飛行模式
主要缺點
- 沒有本地緩存,Picasso的設計上是將緩存交給了Square的另一個庫
OkHttp
,這樣的好處是可以通過請求 Response Header 中的 Cache-Control 及 Expired 控制圖片的過期時間。 - 內存佔用量相對較大,甚至容易出現內存泄露,參見這個測試。
Glide
功能和優點
Glide總體設計圖
- 支持多種媒體格式,包括Gif、WebP、縮略圖,甚至Video。所以Glide實際上可以看作一個媒體緩存
- 支持優先級處理
- Glide的設計注重平滑的滑動,所以即使在列表中使用也非常流暢
- 支持圖片的轉碼(
toBytes()
和transcode()
)和淡入淡出(crossFade
)效果 - 支持同步和異步加載
- 內置生命週期管理,支持Context(Activity、Fragment)調用,並提供了可供擴展的trimMemory接口。
- 支持網絡連接配置,默認使用
UrlConnection
,也可以配合OkHttp
或者Volley
使用。 - 內存友好,包括自動清理內存緩存、緩存圖片尺寸、默認使用
RGB_565
等。以至於Google官方把使用Glide作爲App性能優化的典範,視頻戳這裏:Performance optimisations for android applications - Part 7 Using Glide image loading framework
主要缺點
- 相對於Square的Picasso和Facebook的Fresco,Glide雖然是由Google員工開發和維護並在Google產品中有一定的應用,但並不是Google的官方加載庫。
Fresco
功能和優點
Fresco的設計和前面幾個庫都大不相同:它自己定義了一個顯示圖片的View(稱爲Drawee
)。大部分功能都可以使用SimpleDraweeView
來實現,並且幾乎所有可配置的屬性都支持XML配置。
- 三級緩存(內存2級,文件1級)
- 支持漸進式JPEG圖片
- 支持Gif和WebP格式
- 支持圓角、Overlay、placeHolder、failure等多種場景顯示。
- 支持圖片預處理(Postprocessor)、縮放和旋轉
- 對於5.0版本以下的設備,Fresco有專門的native內存管理優化
- 支持完全自定義的網絡層
主要缺點
SimpleDraweeView
繼承自ImageView
,但是如果應用程序調用了原生ImageView
的方法,例如setImageBackground
,會使得內部的DraweeHierachy完全丟失。而且在Fresco的中文文檔中明確說明後續版本這個控件可能直接從View
類派生。所以在使用DraweeView時不能使用ImageView的任何API,也不能依賴於其繼承自ImageView甚至View的繼承樹。不支持wrap_content屬性。
SimpleDraweeView
必須顯式指定寬度和高度。與
ScrollView
不兼容。使用RecyclerView
,ListView
,或GridView
沒問題,但是使用ScrollView
會使得Fresco的內存管理失效,極大增加OOM的風險。其他Fresco使用陷阱可以看這裏:Fresco-cn.org據說大列表中滑動會造成UI卡頓……
警察叔叔,是他說的類庫依賴過於龐大。超過14K的方法和2M+的jar包依賴,使得Fresco在需要避免65k方法數的場景變得非常危險。
在0.10.0版本中,官方已經在嘗試解決這個問題,確實有所緩解,但遠沒到解決這個問題的程度。
切換圖片加載庫會很困難。由於大部分功能依賴於
SimpleDraweeView
,因此和使用其他的加載庫的佈局文件會有所區別,導致老項目難以遷移;同時一開始就使用Fresco的新項目,以後無論出於什麼原因需要換庫,同樣會很麻煩。
Glide和Picasso的對比
基礎
Glide 和 Picasso 非常相似,Glide 加載圖片的方式和 Picasso 如出一轍。
雖然兩者看起來一樣,但 Glide 更易用,因爲 Glide 的 with 方法不光接受 Context,還接受 Activity 和 Fragment,Context 會自動的從他們獲取,同時將 Activity/Fragment 作爲 with()參數的好處是:圖片加載會和 Activity/Fragment 的生命週期保持一致,比如 Paused 狀態在暫停加載,在 Resumed 的時候又自動重新加載。
圖像和內存
類型 | Glide | Picasso |
---|---|---|
默認格式 | RGB-565 | ARGB-8888 |
內存開銷 | 小 | 大 |
圖片細節 | 迅速 | 平滑 |
磁盤緩存 | 與ImageView尺寸大小一致,調整尺寸後需要重新加載,可代碼配置爲緩存全尺寸 | 全尺寸 |
特性 | 媒體緩存 | 僅支持圖片緩存 |
結論
- 如果預見項目中會有很多圓角或漸進式JPEG等需求,可以使用Fresco;
- 如果是老項目已經使用了UIL或者Picasso,且依賴較多不容易修改,則可以繼續使用;
- 如果還在糾結如何避免65K方法數,推薦使用Glide代替Fresco
因爲Glide比後者實在輕巧了太多; - 如果是老項目需要換加載庫,推薦使用Glide而不是Fresco, 降低遷移工作量;
- 如果是新項目,不推薦使用已經停止維護的UIL,也不推薦Picasso,推薦使用Glide;
- 如果你是Google粉……不用推薦了,Glide趕緊用!