譯:Google官方教程】高效的加載大Bitmap(位圖)

http://my.oschina.net/ryanhoo/blog/88242 html

譯者:Ryan Hoo java

來源:https://developer.android.com/develop/index.html
android

譯者按: 在Google最新的文檔中,提供了一系列含金量至關高的教程。由於種種緣由而不爲人知,真是惋惜!Ryan將會細心整理,將之翻譯成中文,但願對開發者有所幫助。 緩存

        本系列是Google關於展現大Bitmap(位圖)的官方演示,能夠有效的解決內存限制,更加有效的加載並顯示圖片,同時避免讓人頭疼的OOM(Out Of Memory)。
性能

------------------------------------------------------------------------------------- spa

譯文: .net

          圖像能夠有各類各樣的形狀和大小。在不少狀況下,它們每每會比典型的應用UI界面所須要的更大。例如,系統的Gallery程序展現使用Android設備的攝像頭拍攝的照片的分辨率每每要遠高於設備的屏幕密度。  

        考慮到你所使用的內存有限,理想的狀況是你只會想加載一個分辨率相對較低的圖片到內存中來。低分辨率版本的圖片應該與相應UI組件的尺寸應該是相匹配的。一張高分辨率的圖片並不能帶給你任何可見的好處,卻要佔據着寶貴的內存,以及間接致使因爲動態縮放引發額外性能開銷。  

        這節課將向你演示如何解碼大圖片,經過加載較小的圖片採樣以免超出應用的內存限制。


讀取Bitmap(位圖)的尺寸和類型 翻譯

        BitmapFactory提供了幾種解碼方式(decodeByteArray(), decodeFile(), decodeResource()等等),以便從多種資源中建立一個Bitmap(位圖)對象。能夠根據你的圖片數據來源選擇最合適的解碼方式。這些方法視圖爲構造Bitmap對象分配內存,所以很容易致使OutOfMemory(OOM)異常。每一種解碼方式都有額外的特徵,你能夠經過BitmapFactory.Options類類指定解碼方法。在解碼圖片的時候設置inJustDecodeBounds屬性爲true,能夠避免內存分配,返回的bitmap對象爲null卻能夠設置outWidth, outHeight和outMimeType。這項技術容許你在建立Bitmap(並分配內存)以前讀取圖片的尺寸和類型。 code

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;

        爲了不java.lang.OutOfMemeory異常,在解碼圖片以前就要檢查圖片的尺寸,除非你十分確信圖片資源的尺寸是可預見的而且有着充裕的可用內存。  

將縮小版的圖片加載到內存中  

        如今圖片的尺寸已經知道了,這些信息能夠用來決定是將一個完整尺寸的圖片加載到內存中,仍是應該用一個圖片的子樣原本取代它。這裏有一些可供考慮的因素:  
  • 估計加載全尺寸的圖片所要消耗的內存
  • 在考慮應用中其餘內存需求的狀況下,你願意給加載這個圖片分配的內存空間。
  • 準備加載該圖像的目標ImageView或者UI組件的尺寸
  • 當前設備的屏幕的尺寸和密度

        例如,若是最終只是要在ImageView中顯示一張128*96px大小的縮略圖,直接加載1024*768px的圖片是很是不值得的。 orm

        爲了告訴解碼器如何對圖像進行採樣,加載更小版本的圖片,須要在BitmapFactory.Options對象中將inSampleSize設置爲true。例如,一張分辨率爲2048*1536px的圖像使用inSampleSize值爲4的設置來解碼,產生的Bitmap大小約爲512*384px。相較於完整圖片佔用12M的內存,這種方式只需0.75M內存(假設Bitmap配置爲ARGB_8888)。這裏有一個方法用來計算基於目標高寬的sample size的值:

public static int calculateInSampleSize(
            BitmapFactory.Options options, int reqWidth, int reqHeight) {
    // Raw height and width of image
    final int height = options.outHeight;
    final int width = options.outWidth;
    int inSampleSize = 1;

    if (height > reqHeight || width > reqWidth) {
        if (width > height) {
            inSampleSize = Math.round((float)height / (float)reqHeight);
        } else {
            inSampleSize = Math.round((float)width / (float)reqWidth);
        }
    }
    return inSampleSize;
}


        提示:使用2的次冪來設置inSampleSize值可使解碼器執行地更加迅速、更加高效。可是,若是你想在內存或者硬盤上緩存一個調整過大小的圖片,一般仍是解碼到合適的圖片尺寸更加節省空間。

        要使用這個方法,首先要使用inJustDecodeBoundstrue來解碼尺寸信息,將options傳遞過去使用新的inSampleSize值再次解碼而且要將inJustDecodeBounds值設置爲false

public static Bitmap decodeSampledBitmapFromResource(Resources res, int resId,
        int reqWidth, int reqHeight) {

    // First decode with inJustDecodeBounds=true to check dimensions
    final BitmapFactory.Options options = new BitmapFactory.Options();
    options.inJustDecodeBounds = true;
    BitmapFactory.decodeResource(res, resId, options);

    // Calculate inSampleSize
    options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight);

    // Decode bitmap with inSampleSize set
    options.inJustDecodeBounds = false;
    return BitmapFactory.decodeResource(res, resId, options);
}


        這個方法使得加載任意大小的Bitmap到展現100*100px縮略圖的ImageView中更加簡單,以下代碼所示:


mImageView.setImageBitmap(
	    decodeSampledBitmapFromResource(getResources(), R.id.myimage, 100, 100));
        你能夠根據須要,按照相似的解碼過程,採用適當的BitmapFactory.decode*方法從其餘資源中解碼Bitmap。
相關文章
相關標籤/搜索