圖片的載入和顯示是每個商業APP都避免不了的問題,對於圖片重度依賴類APP,例如桌布類應用,圖片社交類應用,對於圖片的處理將會影響到整個APP的使用者體驗。
在正式瞭解Android中如何優化圖片相關的內容之前,我們先看看Android系統支援的圖片格式。
一、圖片的格式
目前移動端Android平臺原生支援的圖片格式主要有:JPEG、PNG、GIF、BMP和WebP(自Android4.0開始支援),但是在Android應用開發中能夠使用的編解碼格式只有其中三種:JPEG、PNG、WebP,圖片格式可以通過檢視Bitmap類的CompressFormat列舉值來確定。
public enum CompressFormat {
JPEG (0),
PNG (1),
WEBP (2);
CompressFormat(int nativeInt) {
this.nativeInt = nativeInt;
}
final int nativeInt;
}複製程式碼
如果要在應用層使用GIF格式圖片,那麼需要自己引入第三方函式庫進行支援。
(1)、JPEG
JPEG是一種廣泛使用的有失真壓縮影像標準格式,它不支援透明和多幀動畫,一般攝影類作品最終都是以JPEG格式展示,通過控制壓縮比,可以調整圖片的大小。
(2)、PNG
PNG是一種無失真壓縮圖片格式,它支援完整的透明通道,從影像處理領域講,JPEG只有RGB三個通道,而PNG有ARGB四個通道。由於是無失真壓縮,因此PNG圖片佔用空間一般比較大,會無形中增加最終APP的大小,在做瘦身時一般都要對PNG圖片進行處理以減小其佔用的體積。
(3)、GIF
GIF是一種古老的圖片格式,它誕生於1987年,隨著初代網際網路流行開來。它的特點是支援多幀動畫。大家對這種格式肯定不陌生,社交平臺上面傳送的各種動態表情,大部分都是基於GIF來實現的。
(4)、WebP
相對於前面幾種圖片格式,WebP算是一個初生兒,由Google在2010年釋出,它支援有損和無失真壓縮、支援完整的透明通道、也支援多幀動畫,是一種比較理想的圖片格式。目前國內很多主流APP都已經應用了WebP,例如微信、微博、淘寶等。在即保證圖片質量又要限制圖片大小的需求下,WebP應該是首選。
二、圖片的壓縮
目前無論Android平臺還是IOS平臺,大多數APP在搭建介面時使用的幾乎都是PNG格式圖片資源,除非你的專案已經全面支援WebP格式,否則你都會面臨對PNG圖片瘦身的要求,在這裡,我們可以通過幾個工具對PNG圖片進行壓縮來達到瘦身的目的。
(1)、無失真壓縮ImageOptim(https://imageoptim.com)
ImageOptim是一個無損的壓縮工具,它通過優化PNG壓縮引數,移除冗餘後設資料以及非必需的顏色配置檔案等方式,在不犧牲圖片質量的前提下,即減小了PNG圖片佔用的空間又提高了載入的速度。
(2)、有失真壓縮ImageAlpha(https://pngmini.com/)
ImageAlpha是ImageOptim作者開發的一個有損的PNG壓縮工具,相比較而言,圖片大小得到極大的降低,當然圖片的質量同時也會受到一定程度的影響,經過該工具壓縮的圖片,需要經過設計師的檢查才能最終上線,否則可能會影響到整個APP的視覺效果。
(3)、有失真壓縮TinyPNG(https://tinypng.com/)
TinyPNG也是比較知名的有損PNG壓縮工具,它以Web站點的形式提供,沒有獨立的APP安裝包,同所有的有失真壓縮工具一樣,經過壓縮的圖片,需要經過設計師的檢查才能最終上線,否則可能會影響到整個APP的視覺效果。
其實還有很多無失真壓縮工具,例如JPEGMini(www.jpegmini.com/),MozJPEG(imageoptim.com/mozjpeg)等,大家都可以從中選擇適合自己專案的一個就行,主要是在圖片大小和圖片質量之間找到一個折衷點。
(4)、PNG/JPEG轉換為WebP
如果你的APP最低支援到Android4.0,那麼可以直接使用系統提供的能力來支援WebP,如果是4.0以下的系統,也可以通過在APP中整合第三方函式庫例如webp-android-backprot(github.com/alexey-pely…)來實現WebP的支援。根據Google的測試,無失真壓縮後的WebP比PNG檔案少了45%的檔案大小,即使這些PNG檔案經過其他壓縮工具例如ImageOptim(imageoptim.com)壓縮之後,WebP依然可以減少約28%的檔案大小。
WebP轉換的工具可以選擇智圖(zhitu.isux.us/)和iSparta(isparta.github.io/)等;
(5)、儘量使用NinePatch格式的PNG圖
.9.png圖片格式簡稱NinePatch圖,本質上仍然是PNG格式圖片,它是針對Android平臺的一種特殊PNG圖片格式,可以在圖片指定位置拉伸或者填充內容。NinePatch圖的優點是體積小,拉伸不變形,能夠很好的適配Android各種機型。Android SDK自帶了NinePatch圖的編輯工具,位於sdk/tools/draw9patch,點選即可啟動;當然,Android Studio也整合了PNG轉NinePatch的功能,我們只需要右鍵點選某個需要轉換的PNG圖片,在彈出的對話方塊中選擇Create 9-Patch File…即可自動完成轉換。
三、圖片的快取
Android發展到今天,已經出現很多優秀的圖片快取函式庫,開發人員可以根據專案的實際需求進行選擇,傳統的圖片快取方案中設定有兩級快取,分別是記憶體快取和磁碟快取。在Facebook推出的Fresco中,它增加了一級快取,也就是Native快取,這極大地降低了使用Fresco的APP出現OOM的概率。
(1)、BitmapFun
BitmapFun函式庫是Android官方教程中的一個圖片載入和快取示例,對於簡單的圖片載入需求來說,使用BitmapFun就夠了,在早期的Android APP開發中使用較多,後來隨著越來越多成熟強大的函式庫的出現,BitmapFun也漸漸退出實際專案開發的舞臺。但作為一個入門圖片快取的教程,它依然起著不可忽視的作用,畢竟萬變不離其宗。
(2)、Picasso(https://github.com/square/picasso)
Picasso是著名的Square公司眾多開源專案中的一個,以著名畫家畢加索為名,連Sample app都使用畢加索的名畫作為例子。它除了實現圖片的下載和二級快取功能,還解決了常見的一些問題。
- 在adapter中正常的處理Image View 回收和下載的取消。
- 使用盡量小的記憶體實現複雜的圖片變換
在Picasso中,我們使用一行程式碼即可實現圖片下載並渲染到ImageView中。
Picasso.with(context).load("https://ss0.bdstatic.com/5aV1bjqh_Q23odCf/static/superman/img/logo/bd_logo1_31bdc765.png").into(imageView);複製程式碼
(3)、Glide(https://github.com/bumptech/glide)
Glide是Google推薦的用於Android平臺上的圖片載入和快取函式庫。這個庫被廣泛應用在Google的開源專案中,Glide和Picasso有90%的相似度,可以說就是Picasso的克隆版本,只是在細節上還是存在不少區別。Glide為包含圖片的滾動列表做了儘可能流暢的優化。除了靜態圖片,Glide也支援GIF格式圖片的顯示。Glide提供了靈活的API可以讓開發者方便地替換下載圖片所用的網路函式庫,預設情況下,它使用HttpUrlConnection作為網路請求模組,開發者也可以根據自己專案的實際需求靈活使用Google的Volley或者Square的OkHttp等函式庫進行替換。
Glide的使用也可以使用一行程式碼來完成,語句如下,跟Picasso確實非常相似。
Glide.with(this).load("https://ss0.bdstatic.com/5aV1bjqh_Q23odCf/static/superman/img/logo/bd_logo1_31bdc765.png").into(imageView);複製程式碼
(4)、Fresco(https://github.com/facebook/fresco)
Fresco是Facebook開源的功能強大的圖片載入和快取函式庫,相比其他圖片快取庫,Fresco最顯著的特點是具有三級快取:兩級記憶體快取和一級磁碟快取。它的主要特性如下。
- 漸進式地載入JPEG圖片。
- 顯示GIF和WebP動畫。
- 可擴充套件,可自定義的圖片載入和顯示。
- 在Android4.x和以下的系統上,將圖片放在Android記憶體一個特殊的區域,從而使得應用執行更流暢,同時極大減低出現OutOfMemoryError錯誤。
(5)、Android-Universal-Image-Loader(https://github.com/nostra13/Android-Universal-Image-Loader)
Android-Universal-Image-Loader簡稱UIL,是Android平臺老牌的圖片下載和快取函式庫,功能強大靈活且高度可自定義,它提供一系列配置選項,並能很好地控制圖片載入和快取的過程。使用者甚多,早期的Android開發者應該都接觸過,現在仍然在很多專案中使用。UIL也支援二級快取,它的主要特性如下。
- 同步或者非同步的多執行緒圖片載入。
- 高度可自定義:執行緒池、下載器、解碼器、記憶體和磁碟快取、圖片顯示選項等。
- 每張圖片的顯示支援多種自定義選項:預設存根圖片、快取切換、解碼選項、Bitmap處理和顯示等。
- 圖片可快取在記憶體或者磁碟(裝置的檔案系統或者SD卡)上;
- 可實時監聽圖片載入流程,包括下載進度。
最後來看一下如果引入這些函式庫,會給APP增加多大的空間:
可以看到,Fresco函式庫的依賴庫有很多,除了他幾個函式庫的jar以外,其他的都是使用Fresco所需要依賴的。總結起來,以上函式庫大小如下:
- Picasso:118kb
- Glide:465kb
- Fresco:770kb
- Android-Universal-Image-Loader:159kb
圖片函式庫的選擇需要根據APP的具體情況而定,對於嚴重依賴圖片快取的APP,例如桌布,圖片社交類APP來說,可以選擇最專業的Fresco。對於一般的APP,選擇Fresco會顯得比較重,畢竟Fresco 770kb的體量擺在這兒。根據APP對圖片顯示和快取的需求從低到高我們可以對以上函式庫做一個排序。
Picasso<Android-Universal-Image-Loader<Glide<Fresco
值得一提的是,如果你的APP計劃使用React Native 進行部分模組功能的開發的話,那麼在基礎函式庫選擇方面需要考慮和React Native的依賴庫的複用,這樣可以減少引入React Native 所增加的APP大小,可以複用的函式庫有:OkHttp、Fresco、jackson-core。