Bitmap 載入耗時長、佔用內存高,如何優化?
前言
圖片是移動端開發中司空見慣的內容,開發者多數時候都會涉及圖片載入的功能。Bitmap是圖片在Android中的一種承載方式,它可以被載入到需要展示圖片的地方,比如ImageView或是View的background。隨著移動設備的更新換代,圖片的解析度越來越高,載入Bitmap的時候就不得不考慮OOM的問題了。
1
Bitmap Factory
Android中Bitmap的載入一般是通過BitmapFactory類來實現的。BitmapFactory類提供多種載入方式,常用的幾個載入方式:
文件
資源
位元組數組
數據流
2
Problem
通常,直接調用BitmapFactory的上述幾個方法,傳遞相對應的參數就可以載入Bitmap了。Bitmap對象在Android應用程序中佔用的內存是非常高的。
一張480x800的圖片,Bitmap佔用內存計算:
不作任何處理,直接調用BitmapFactory的decode方法來載入Bitmap會有幾個問題:
圖片解析度高,Bitmap載入耗時長;
圖片解析度高,Bitmap佔用內存很高,可能出現OOM;
圖片數量很多,Bitmap佔用內存很高,可能出現OOM。
3
Solution
不知道大家注意到沒有,上述幾個decode方法都有一個共同的參數——Options,它其實是BitmapFactory的一個內部類,主要提供Bitmap載入配置參數。我們今天要討論的優化點就是從Options配置參數出發,減少Bitmap載入過程中的內存消耗,降低Bitmap載入耗時,盡量降低OOM出現的風險。
Options參數源碼
提取Options關鍵配置參數,看看源碼如何描述的:
Options參數分析
結合兩個參數的含義,要降低Bitmap內存佔用,需要根據期望圖片尺寸和原圖尺寸來計算最佳圖片採樣率,使得圖片在不失真的情況下內存佔用盡量小,然後使用計算出的最佳圖片採樣率來decode圖片bitmap,達到降低Bitmap內存佔用及減少decode操作耗時的目的。
??
那麼,如何能夠快速又不消耗內存地得到原圖尺寸呢?答案就是利用inJustDecodeBounds參數!設置Options的inJustDecodeBounds參數為true,此時執行一次decode操作即可在不消耗內存的條件小拿到原圖尺寸。
4
解決方案
??
結合上述Options參數分析,我們可以寫出一個簡單的解決方案:
計算期望圖片尺寸
??
如何計算呢?
??
假設我們最終要decode的bitmap尺寸是長(maxWidth)和寬(maxHeight),然後根據原圖尺寸的長寬比來按比例縮放計算,得到縮放後的期望尺寸desiredWidth和desiredHeight。為什麼要這麼做呢?因為預設的maxWidth和maxHeight,它們的比例並不一定跟原圖比例相符,按比例縮放後的期望尺寸才能保證最終圖片不變形。
??
具體演算法如下:
計算最佳圖片採樣率
??
根據前面對inSampleSize參數的解析,它的最終取值為2的指數倍。結合期望尺寸和原圖尺寸的比值,我們可以計算出一個最接近該比值的採樣率數值,把它作為最佳採樣率。
Powers of 2 : 2^n
2^0 = 1
2^1 = 2
2^2 = 4
2^3 = 8
2^4 = 16
2^5 = 32
2^6 = 64
2^7 = 128
2^8 = 256
2^9 = 512
2^10 = 1024
具體演算法如下:
5
最終實現
??
上述的解決方案經過我們的分解之後,一步一步實現了,最終的代碼實現如下:
6
結語
隨著Android系統越來越高度成熟,各種開源項目也層出不窮,在圖片載入這塊上就已經有很多優秀的開源項目了,比如早期的Android-Universal-Image-Loader,FackBook開源的Fresco以及Google開發人員開源的Glide(現已被Google採用)。
今天分享的Bitmap載入性能優化方案,也可以運用到項目工程中,比如圖片上傳功能模塊,既可以減少選擇圖片後的等待耗時,又可以上傳壓縮後的圖片文件,達到性能和體驗雙收目的。
「魅族開放平台」每周推出一篇魅族工程師的分享,如果覺得文章不錯,就請分享給身邊的朋友們吧,歡迎留言討論~
TAG:魅族開放平台 |