Android面試集錦系列(16)——圖片到底是什麼
現在應用很難離開圖片,就像美女上網不能少“美顏”工具一樣。以前的手機記憶體空間比較小,每個程序能使用的堆記憶體往往只有32M(有的只有16M,如G1手機),所以會發現加幾張大圖之後,系統一言不合就給你個OutOfMemoryError。不過,現在的手機一般堆記憶體都比較多了(看過一些手機基本上都接近200M),其實對於現在的APK動不動就幾十M以上也不算特別富餘,記憶體的使用還是要謹慎合理,特別是在處理圖片的時候。
面試題:有沒有遇到Bitmap OOM的問題?如何優化圖片佔用的記憶體空間?
我覺得在回答上述問前,我們首先要回答一個問題:
Android系統上的圖片指的是什麼?
首先看Android支援的圖片格式:
Android支援JPEG和PNG格式的圖片,4.0之後添加了WEBP圖片的支援(不過有些手機產商並不一定支援,如小米2S 4.1的SDK版本,但還是顯示不了WEBP格式),5.0之後增加了對GIF和BMP圖片的支援。
其實圖片最終要顯示在螢幕上,都會對應一個螢幕上的點,即對應一個顏色值。不同格式的圖片,只是不同壓縮編碼和解壓演算法。也就是說,我們看到的.jpg、.png圖片的檔案大小隻有幾十KB,擔把它們載入到記憶體中時,每張圖片最終都按長X寬展開,計算其佔用記憶體大小的就變成了(ARGB_8888格式的圖片,每畫素佔用 4 Byte,而 RGB565則是 2 Byte,假設是ARGB_8888):
記憶體佔用=長 X 寬 X 4bytes
這種演算法其這還忽略螢幕的Density,如我們上Day 21的面試題中也提到過的,放在不同的drawable目錄中的圖片顯示時會根據Denisty有一定的縮放。所以有時候圖片佔用的記憶體會比我們上面公式計算出來的還要大很多。
Bitmap和Drawable
Bitmap是Android系統中的影象處理的最重要類。可以簡單地說,Bitmap代表的是圖片資源在記憶體中的資料結構,如它的畫素資料,長寬等屬性都存放在Bitmap物件中。Bitmap類的建構函式是私有的,只能是通過JNI例項化,系統提供BitmapFactory工廠類給我們從從File、Stream和byte[]建立Bitmap的方式。
Drawable官文文件說明為可繪製物件的一般抽象。View也是可以繪製的,但Drawable與View不同,Drawable不接受事件,無法與使用者進行互動。我們知道很多UI控制元件都提供設定Drawable的介面,如ImageView可以通過setImageDrawable(Drawable drawable)設定它的顯示,這個drawable可以是來自Bitmap的BitmapDrawable,也可以是其他的如ShapeDrawable。
也就是Drawable是一種抽像,最終實現的方式可以是繪製Bitmap的資料或者圖形、Color資料等。理解了這些,你很容易明白為什麼我們有時候需要進行兩者之間的轉換。
優化手段
在Android 3.0之前的版本,Bitmap畫素資料存放在Native記憶體中,而且Nativie記憶體的釋放是不確定的,容易記憶體溢位而Crash,所以一般我們不使用的圖片要呼叫recycle()。

從3.0開始,Bitmap畫素資料和Bitmap物件一起存放在Dalvik堆記憶體中(中從原始碼上看是多了一個byte[] buffer用來存放資料),也就是我們常說的Java Heap記憶體。

除了這點改變之外,3.0版本的還增加了一個inBitmap屬性(BitmapFactory.Options.inBitmap)。如果設定了這個屬性則會重用這個Bitmap的記憶體從而提升效能。但是這個重用是有條件的,在Android4.4之前只能重用相同大小的Bitmap,Android4.4+則只要比重用Bitmap小即可。
當然優化的手段還有很多,比如使用取樣率(inSampleSize),如果最終要壓縮圖片,如顯示縮列圖,我們並不需要載入完整的圖片資料,只需要按一定的比例載入即可;使用Matrix變形等,比如使用Matrix進行放大,雖然影象大了,但並沒有佔用更多的記憶體。
使用第三方圖片庫也是一種優化吧,它們幫我們完成了很多工作。Facebook的Fresco還自己開闢了Native記憶體用於儲存圖片,以得到更大的記憶體空間(其實我還不確認這種方式是否有相容性問題)。
要載入很大的圖片怎麼辦?
如果圖片很大,比如他們的佔用記憶體算下來就直接OOM了,那麼我們肯定不能直接載入它。解決主法還是有很多的,系統也給我們提供了一個類BitmapRegionDecoder,可以用來分塊載入圖片。
小結
雖然網上有很多開源的和圖片相關的庫,但我們還是有必要了解一下Bitmap的相關的知識的,有時候我們只需要一個簡單的功能,可以手動自己實現,不一定非要加進一個開源庫。程式碼越是簡單,可控性和可維護性越好,對吧。
最後
在這裡我總結出了網際網路公司Android程式設計師面試簡歷模板,面試涉及到的絕大部分面試題及答案做成了文件和架構視訊資料免費分享給大家【 包括高階UI、效能優化、架構師課程、NDK、Kotlin、混合式開發(ReactNative+Weex)、Flutter等架構技術資料 】,希望能幫助到您面試前的複習且找到一個好的工作,也節省大家在網上搜索資料的時間來學習。
資料獲取方式:加入Android架構交流QQ群聊:513088520 ,進群即領取資料!!!
點選連結加入群聊【Android移動架構總群】: 加入群聊

資料大全