流暢的載入大的Bitmap
原文串連 http://developer.android.com/intl/zh-CN/training/displaying-bitmaps/load-bitmap.html#read-bitmap
在處理Bitmap的過中經常遇到的問題是OOM,尤其是在載入像素比較大的bitmap時,出現這種問題的機率比較高。在載入圖片的時候,就要考慮是否真的需要那麼大像素的bitmap,如果要顯示的ImageView的大小是120x140,但是要載入的資源的圖片是1024X768的,這時候如果直接載入資源很容易出現OOM的問題,如果在載入圖片之前能夠知道圖片的像素的大小,然後在適當的壓縮處理,然後在顯示出來,這樣OOM的問題就比較不容易出現。
讀取Bitmap的大小和類型
BitmapFactory提供了很多方法來解析方法(decodeByteArray(), decodeFile(), decodeResource()等等)來建立bitmap,你可以選擇一個合適的方法來建立bitmap,但是這樣直接的建立bitmap和容易引起OOM,BitmapFactory還提供一組配套的方法來建立bitmap,需要加上BitmapFactory.Options的參數,在顯示bitmap之前事先讀取bitmap的大小和類型:
BitmapFactory.Options options = new BitmapFactory.Options();options.inJustDecodeBounds = true;BitmapFactory.decodeResource(getResources(), R.drawable.myimage, options);int imageHeight = options.outHeight;int imageWidth = options.outWidth;String imageType = options.outMimeType;
將BitmapFactory.Options的inJustDecodeBounds設定為true,可以在解析bitmap之前獲得bitmap的大小和類型
壓縮bitmap之後,再載入到記憶體
在顯示bitmap之前,需要獲得目標顯示的bitmap的大小和要載入的bitmap的大小,然後計算出來一個合適的壓縮比,把通過壓縮過的bitmap載入到記憶體中,下面是一個封裝的方法,來計算合適的壓縮比
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) { // Calculate ratios of height and width to requested height and // width final int heightRatio = Math.round((float) height / (float) reqHeight); final int widthRatio = Math.round((float) width / (float) reqWidth); // Choose the smallest ratio as inSampleSize value, this will // guarantee // a final image with both dimensions larger than or equal to the // requested height and width. inSampleSize = heightRatio < widthRatio ? heightRatio : widthRatio; } return inSampleSize; }
其中 reqWidth,reqHeight是目標的寬的和高度,height,width是資源的高度和寬的,然後計算出一個壓縮的比例,使用最小的壓縮比
要使用這個方法,首先將inJustDecodeBounds 設定為true,解析獲得資源的大小和類型,然後通過上面的方法獲得壓縮比,然後再將inJustDecodeBounds設定為false,通過計算出來的要所比來解析最終要顯示的bitmap
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); }
例子: imageView的顯示,ImageView要顯示的映像的大小是100X100,實際的映像可能不是100X100,通過上面的方法做一下壓縮處理,這樣就避免出現OOM的問題 mImageView.setImageBitmap(
decodeSampledBitmapFromResource(getResources(), R.drawable.myimage, 100, 100)); 上面是通過解析decodeSampledBitmapFromResource 資源檔獲得bitmap,當然還有其他的方法來獲得bitmap
- 通過檔案獲得bitmap
public static Bitmap decodeSampledBitmapFromFile(String filename, int reqWidth, int reqHeighte) { // First decode with inJustDecodeBounds=true to check dimensions final BitmapFactory.Options options = new BitmapFactory.Options(); options.inJustDecodeBounds = true; BitmapFactory.decodeFile(filename, options); // Calculate inSampleSize options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight); // Decode bitmap with inSampleSize set options.inJustDecodeBounds = false; return BitmapFactory.decodeFile(filename, options);
2.通過FileDescriptor獲得bitmap
public static Bitmap decodeSampledBitmapFromDescriptor( FileDescriptor fileDescriptor, int reqWidth, int reqHeight, ImageCache cache) { // First decode with inJustDecodeBounds=true to check dimensions final BitmapFactory.Options options = new BitmapFactory.Options(); options.inJustDecodeBounds = true; BitmapFactory.decodeFileDescriptor(fileDescriptor, null, options); // Calculate inSampleSize options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight); // Decode bitmap with inSampleSize set options.inJustDecodeBounds = false; return BitmapFactory.decodeFileDescriptor(fileDescriptor, null, options); }