Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> Android進階練習 - 高效顯示Bitmap(高效加載較大的 Bitmaps)

Android進階練習 - 高效顯示Bitmap(高效加載較大的 Bitmaps)

編輯:關於Android編程

高效加載較大的 Bitmaps


     圖片有各種形狀和各種大小,在很多情況下,圖片的實際大小都比圖片在應用中所顯示的大小要大的多,比如Android系統自帶的 Gallery  應用顯示的照片實際的分辨率通常比手機設備的密度要高很多


     考慮到我們是在開發一款內存使用受限的應用,理想的情況下,我們只是想把一個低分辨率版本的位圖載入內存,一般來說這個低分辨率版本的位圖要跟UI元件實際需要顯示的大小相符。一張高分辨率的圖片並不會給我們帶來任何明顯的好處,但卻會占用寶貴的內存資源和產生額外的性能開銷


獲取Bitmap的尺寸大小和類型


     BitmapFactory 類為我們提供了幾種decoding方法(decodeByteArray(), decodeFile(),decodeResource(), etc)來從不同的來源創建出 Bitmap ,如何選擇最恰當的decode方法取決於你的圖片數據來源,這些方法都會去嘗試申請內存來構建Bitmap對象,所有很容易就會導致一個OutOfMemory  異常,每種類型的decode方法都有額外的簽名來讓你通過 BitmapFactory.Options 類來指定decoding選項,當我們decoding的時候把inJustDecodeBounds 屬性設置為true 可以避免申請內存,雖然會返回一個null Bitmap對象 ,但是會為我們傳入的BitmapFactory.Options  對象設置 outWidth, outHeight and outMimeType 等屬性的值,這個技術可以讓你在構建Bitmap對象之前事先知道它的大小和類型


[java]
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; 

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.OutOfMemory  異常,在decoding Bitmap之前你有必要去檢測Bitmap的大小和類型,除非你真的是非常清楚你要decoding的Bitmap的大小,還有這個大小要適合當前應用內存環境


載入‘縮小版’的Bitmap到內存


     現在我們已經知道了Bitmap的大小,這將有助於我們來決策是載入整張Bitmap還是載入'縮小版'的Bitmap,這裡有一些因素需要進行考慮


            一、載入整張圖片預計要使用多少內存
            二、在考慮到其它方面內存需要的情況下,你想把多少數量的內存給Bitmap使用
            三、用於顯示Bitmap的 ImageView 控件或其它UI元件的大小
            四、當前設備屏幕的大小和密度
    
例如,一點都不值得載入1024x768  像素的圖片到內存中,而最終只在128x96 像素大小的 ImageView 控件上顯示 
    
     我們應該告訴decoder,圖像需要進行抽樣,載入一個更小號的Bitmap到內存中,設置 BitmapFactory.Options 對象的 inSampleSize 屬性為true 。例如,一張分辨率為2048x1536 像素的圖片,如果decode的時候把inSampleSize   設置為4,那麼得到的最終圖片的大小大約為512x384 ,載入內存耗費0.75M而不是載入整張時的12M (假設位圖的配置為 ARGB_8888) ,下面有一個在目標高和寬基礎上計算inSampleSize 的方法


[java]
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; 

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;
}
NOTE :  inSampleSize  值是2的冪的話,對於decoder來說會更快和更高效。然而,如果你想把調整過大小的位圖緩存到內存或硬盤上時,依然非常有意義decoding最合適的位圖大小,這樣有助於節省內存或節省硬盤空間


下面是一個獲取位圖的方法
[java]
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); 

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);
}


這個方法可以很容易的做到在任意顯示尺寸大小的UI元件中去載入一張位圖
[java]
mImageView.setImageBitmap( 
    decodeSampledBitmapFromResource(getResources(), R.id.myimage, 100, 100)); 

mImageView.setImageBitmap(
    decodeSampledBitmapFromResource(getResources(), R.id.myimage, 100, 100));


在其他的BitmapFactory.decode*  系列的decode方法中以上獲取位圖的技術也是需要的

 

 

 

 

 

 

 

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved