Android高效內存之讓你的圖片省內存

Android高效內存之讓你的圖片省內存

       在作內存優化的時候,咱們發現除了解決內存泄露問題,剩下的就只有想辦法減小真實的內存佔用。而在App中,大部份內存可能被咱們圖片佔用了,因此減小圖片的內存佔用能夠帶來直接的效果。java

1、一張圖片到底佔用多少內存

  咱們先假設咱們有一張圖片是600 * 800像素的,圖片磁盤佔用空間大小假設是 100KB。android

圖片內存大小跟磁盤佔用空間大小有什麼關係?優化

  磁盤佔用空間的大小不是圖片佔用內存的大小,磁盤佔用空間是在磁盤上存儲圖片須要的一個空間大小,內存大小是加載到內存中佔用的內存大小。兩個只是單位是同樣的,本質不是一個概念。編碼

一張圖片到底佔用多少內存呢?spa

  圖片佔用內存的計算公式是:圖片高度 * 圖片寬度 * 一個像素佔用的內存大小,在Android中通常狀況下默認一個像素佔用內存是4個字節,因此上面的圖片佔用內存是:800 * 600 * 4 byte = 1875KB = 1.83M。爲何是4個字節呢?必定是4個字節麼?這兩個問題後面仔細講。code

圖片所在目錄對內存的影響?對象

  在Android中,圖片的存放目錄和手機的屏幕密度影響圖片最終加載到內存的實際大小,舉個例子:假設咱們的圖片放到xhdpi目錄下,那麼咱們本文中的圖片佔用的內存大小以下.blog

  • 屏幕密度爲2的設備:800 * 600 * 4byte = 1.83M
  • 屏幕密度爲3的設備:800 * 1.5 * 600 * 1.5 * 4byte = 1.83 * 2.25M = 4.12M
  • 這裏所說的屏幕密度是指android.util.DisplayMetrics類中的density變量,是一個float值,關於屏幕密度的更多內容本文不作介紹。

  

  因此,計算圖片佔用內存大小的時候,要考慮圖片所在的目錄跟屏幕密度,這兩個因素其實影響的是圖片的高寬,Android會對圖片進行拉昇跟壓縮。圖片

2、 讓你的圖片省內存

2.1 讓你的圖片最小化

  圖片的內存佔用計算方式爲:圖片高度 * 圖片寬度 * 一個像素佔用的內存大小,因此圖片的高寬若是都變爲原來寬高的2倍,那麼內存將變爲原來的4倍。因此圖片的使用原則能夠總結以下:內存

  1. 使用盡量小的圖
  2. 使用.9圖,.9圖自己也要儘量的小
  3. 本身繪製(覆寫View的onDraw本身畫)或者使用Drawable來繪製

好比要實現一個線性漸變效果能夠採用如下drawable實現:

 

2.2 在內存中壓縮圖片

  加載大圖片時須要對圖片進行壓縮,使用等比例壓縮方法直接在內存中處理圖片。

Options options = new BitmapFactory.Options();
options.inSampleSize = 5; // 原圖的五分之一,設置爲2則爲二分之一
Bitmap bitmap = BitmapFactory.decodeResource(getResources(),
                       R.id.myimage, options);

  這樣作要注意的是,圖片質量會變差,inSampleSize設置的值越大,圖片質量就越差。

2.3 讀取位圖尺寸和類型時不把圖片加載到內存中

  有時候咱們取得一張圖片,也許只是爲了得到這個圖片的一些信息,好比圖片的width、height等信息,不須要顯示到界面上,這個時候咱們能夠不把圖片加載到內存中。

BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeResource(getResources(), R.id.myimage, options);
int imageHeight = options.outHeight;
int imageWidth = options.outWidth;
String imageType = options.outMimeType;

2.4 用完就回收

  因爲Android外層是使用java,而底層使用的是C語言爲圖片對象分配的內存空間。因此咱們的外部雖然看起來釋放了,但裏層卻並不必定徹底釋放了,咱們使用完圖片後最好再釋放掉裏層的內存空間。

if (!bitmapObject.isRecyled()) {    // Bitmap對象沒有被回收
    bitmapObject.recycle();         // 釋放
    System.gc();                    // 提醒系統及時回收
}

2.5 下降要顯示的圖片色彩質量

2.5.1 顏色模型

RGB(ARGB)

  RGB色彩模式是工業界的一種顏色標準,是經過對紅(R)、綠(G)、藍(B)三個顏色通道的變化以及它們相互之間的疊加來獲得各式各樣的顏色的,RGB便是表明紅、綠、藍三個通道的顏色,這個標準幾乎包括了人類視力所能感知的全部顏色,是目前運用最廣的顏色系統之一。在Android中還有包含透明度Alpha的顏色模型,即ARGB。

 

2.5.2 RGB在計算機中顏色值的數字化編碼

  在不考慮透明度的狀況下,一個像素點的顏色值在計算機中的表示方法有如下3種:

  1. 浮點數編碼:好比float: (1.0, 0.5, 0.75),每一個顏色份量各佔1個float字段,其中1.0表示該份量的值爲全紅或全綠或全藍。
  2. 24位的整數編碼:好比24-bit:(255, 128, 196),每一個顏色份量各佔8位,取值範圍0-255,其中255表示該份量的值爲全紅或全綠或全藍。
  3. 16位的整數編碼:好比16-bit:(31, 45, 31),第1和第3個顏色份量各佔5位,取值範圍0-31,第2個顏色份量佔6位,取值範圍0-63。

  在Java中,float類型的變量佔32位,int類型的變量佔32位,short和char類型的變量都在16位,所以能夠看出,用浮點數表示法編碼一個像素的顏色,內存佔用量是96位即12字節;而用24位整數表示法編碼,只要一個int類型變量,佔用4個字節(高8位空着,低24位用於表示顏色);用16位整數表示法編碼,只要一個short類型變量,佔2個字節;所以能夠看出採用整數表示法編碼顏色值,能夠大大節省內存,固然,顏色質量也會相對低一些。在Android中獲取Bitmap的時候通常也採用整型編碼。

2.5.3 Android中RGB編碼格式(整型編碼)

  • RGB888(int):R、G、B份量各佔8位
  • RGB565(short):R、G、B份量分別佔五、六、5位
  • RGB555(short):RGB份量都用5位表示(剩下的1位不用)
  • ARGB8888(int):A、R、G、B份量各佔8位
  • ARGB4444(short):A、R、G、B份量各佔4位

  在Android的Bitmap.Config類中,有ARGB_888八、ARGB_444四、RGB565等常量,如今能夠知道它們分別表明了什麼含義。

 

  在Android中系統默認使用的編碼格式是ARGB_8888,因此在文章開頭計算圖片內存大小的時候每一個像素佔用內存大小是4byte,好比採用ARGB_8888編碼載入一張1920*1200的圖片,大概就會佔用1920*1200*4/1024/1024=8.79MB的內存。

2.5.4 下降要顯示的圖片色彩質量

  採用低內存佔用量的編碼方式,好比Bitmap.Config.ARGB_4444比Bitmap.Config.ARGB_8888更省內存,好比1920*1200的圖片。

  • ARGB_8888:1920*1200*4/1024/1024=8.79MB
  • ARGB_4444,RGB565:1920*1200*2/1024/1024=4.39MB

3、總結

  在Android中,對圖片的使用必定要關注,大多數狀況下,佔用內存多,OOM發生都是由於圖片資源使用不當。不要盲目加一個大圖到Android項目中,能使用.9進來使用,並且.9圖自己儘量小,另外能使用繪製實現就不要加一個圖片資源。有些時候,在不影響用戶體驗的狀況下,能夠下降圖片色彩質量,好比不須要透明度的就不要了,有些透明度用肉眼看不出來。

相關文章
相關標籤/搜索