Android圖片加載解析之Bitmap

寫在前面的話,本篇文章是參考自《Android開發(fā)藝術探索》所寫,看此書已是2015年的事情啦,由于獨立開放項目,以至于對于Android原理性東西生疏,最近需要換工作,重新?lián)炱鸫藭?,仍有大的收獲。故在此留下一筆。(總結是很有必要的)

在Android圖片加載方面,我們少不了與Bitmap(位圖)打交道,但是與它相處需要步步謹慎啊,稍不留神就跟OOM(內(nèi)存溢出)見面啦。
> java.lang.OutofMemoryError:bitmap size exceeds VM budget
如何高效地加載Bitmap是我們每一個開發(fā)者都不容忽視的問題。
下面我們來逐步地深入探討這個問題:

一:如何加載Bitmap

Bitmap在Android中簡單理解為一張圖片,圖片的格式可以是(JPEG ,PNG ,WEBP等)。

BitmapFactory為我們提供了4類方法來加載Bitmap:
1.decodeFile();
2.decodeResource();
3.decodeStream();
4.decodeByteArray();

看圖更明白一些:

Bitmap加載方式.png

如果深入去查看這些方法,會發(fā)現(xiàn)其中** decodeFile()和decodeResource()都間接調(diào)用了decodeStream()。這四類加載方法最終都是在Android低層實現(xiàn)的,對應著BitmapFactory類的幾個native方法。
到了這里,Bitmap的簡單加載就介紹完畢,但是Bitmap的加載遠沒有結束,因為如果我們這么簡單使用,會經(jīng)常與
OOM**邂逅。這就需要進行高效設置啦。

二:如何高效地加載Bitmap

首先來交代一下背景:其實所謂高效,只不過就是不浪費系統(tǒng)那寶貴的資源。在Android開發(fā)中,與Bitmap打交道最多的控件要屬ImageView。在很多情況下,ImageView都沒有圖片的原始尺寸那么大,這時如果我們不加任何設置而直接讓ImageView來顯示圖片。Android系統(tǒng)往往都是先將整個圖片加載到內(nèi)存,然后再顯示出來。這顯然是畫蛇添足。

我們可以通過BitmapFactory.Options來通過設置采樣率來加載所需尺寸的圖片,這樣就降低內(nèi)存占用從而在一定程度上降低了OOM的發(fā)生率。BitmapFactory提供的加載圖片的四類方法都支持BitmapFactory.Options參數(shù),通過它我們就可以很方便地進行采樣縮放。(意不意外,驚不驚喜?)
那么我們是如何通過BitmapFactory.Options來進行采樣縮放的呢?
這里主要用到了inSampleSize這個變量;

采樣率.png

從圖上的注釋我們可以知道:

  • 如果inSampleSize > 1,將會給我們返回一個比原圖更小的圖片來節(jié)約內(nèi)存。舉個例子,當設置 inSampleSize = 4時,那么采樣后的圖片其寬和高都縮小為原圖的1/4,而像素數(shù)為原圖的1/16,這樣其所占用的內(nèi)存也只有原來的1/16。
  • 當 inSampleSize <= 1時,系統(tǒng)都會當成1來對待;
  • 這個inSampleSize 的取值應該總為2 的指數(shù)(1,2,4,8,18...),如果外界傳遞給系統(tǒng)的inSampleSize不為2的指數(shù),則系統(tǒng)會向下取整并選擇一個最接近2的指數(shù)來代替。

獲取采樣率的流程:

  1. 獲取BitmapFactory.Options的對象;
  1. 將BitmapFactory.Options的inJustDecodeBounds參數(shù)設置為true并加載圖片;
  2. 從BitmapFactory.Options中取出原始圖片的寬高信息,即outWidth和outHeight參數(shù)。
  3. 根據(jù)采樣率的規(guī)則并結合目標View的所需大小計算采樣率inSampleSize。
  4. 將BitmapFactory.Options的inJustDecodeBounds參數(shù)設置為false,然后重新加載圖片。

針對于inJustDecodeBounds這個變量:

將 inJustDecodeBounds參數(shù)設置為ture時,BitmapFactory只會解析圖片的原始寬高信息,并不會真正地加載圖片,所以這個操作是輕量級的。

    "Talk is cheap. Show me the code."           - Linus Torvalds
  // 從res中加載bitmap
 public static Bitmap decodeBitmapFromRes(Resources res,int resId,
                                             int requestWidth,
                                             int requestHeight){
        BitmapFactory.Options options = new BitmapFactory.Options();
        options.inJustDecodeBounds = true;
        BitmapFactory.decodeResource(res,resId,options);
      
        //設置采樣率
        options.inSampleSize = calculateInSampleSize(options,requestWidth,requestHeight);
        
        options.inJustDecodeBounds = false;
        
        return BitmapFactory.decodeResource(res,resId,options);
    }

//計算采樣率
 private static int calculateInSampleSize(BitmapFactory.Options options, 
                                             int requestWidth, 
                                             int requestHeight) {
        int outWidth = options.outWidth;
        int outHeight = options.outHeight;

        int inSampleSize = 1;

        if(outHeight>requestHeight || outWidth > requestWidth){
            int halfHeight = outHeight / 2;
            int halfWidth = outWidth / 2;

            while ((halfHeight/ inSampleSize) >= requestHeight
                    && (halfWidth / inSampleSize) >= requestWidth){
                inSampleSize *= 2;
            }
        }
        return inSampleSize;
    }

到此,Bitmap加載可以在實際開發(fā)工作中使用啦。

最后編輯于
?著作權歸作者所有,轉載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容