Bitmap的加載和Cache(存儲)

Bitmap 的加載和Cache

Bitmap的高效加載(圖片的壓縮)

OOM

由於Bitmap的特殊性以及Android對單個應用所施加的內存限制,比如16M這導致加載Bitmap的時候很容易就出現內存溢出.
java.lang.OutofMemoryError:bitmap size exceeds VM budget

所以我們需要多圖片進行壓縮,這樣就不會佔用多餘的內存空間.

如何加載一張圖片

Bitmap在Android中指的是一張圖片,比如JGP,PNG,以及其他的格式的圖片. 
BitmapFactory 類提供了四類方法,
  1. decodeFile 文件系統
  2. decodeResource 資源
  3. decodeStream 輸入流
  4. decodeByteArray 字節數組

如何高效的加載一張圖片呢

核心思想就是,採用BimapFactory.Options來加載圖片所需的尺寸的圖片. 將縮小後的圖片在ImageView中顯示,這樣就降低內存佔用率,從而一定程度上避免OOM

BitmapFactory.Options 主要用到了inSampleSize(採用率)

  • inSampleSize==1 原圖顯示
  • inSampleSize==2 寬高爲原來的1/2 , 圖片爲原來的1/4

    inSmpleSize 只能是1,2,4,8,16, 2的指數,如果不是的話就去最接近2的指數的數值.

如何獲取採用率?

  1. 將BitmapFactory.Options的inJustDecodeBounds參數設爲true並加載圖片
  2. 從BitmapFactory.Options中取出圖片的原始寬高信息,他們對應於outWidth和outHeight參數
  3. 根據採樣率的規則並結合目標View的所需大小計算出採樣率
  4. 將BitmapFactory.Options 的 inJustDecodeBounds 的參數設置爲false,然後重新加載圖片
//可以直接當作工具類來使用
public class BitmapResizer {

    private static final String TAG = "BitmapResizer";

    public BitmapResizer() {
    }


    /**
     * TODO 通過Resource資源,來加載縮放圖片.
     * @author msh
     * @time 2016/10/22 11:13
     *
    */
    public Bitmap decodeSampledBitmapFromResource(Resources res,
                                                  int resId, int reqWidth, int reqHeight) {
        final BitmapFactory.Options options = new BitmapFactory.Options();

        //1,將BitmapFactory.Options的inJustDecodeBounds參數設爲true並加載圖片
        options.inJustDecodeBounds = true;
        BitmapFactory.decodeResource(res, resId, options);


        //2,從BitmapFactory.Options中取出圖片的原始寬高信息,他們對應於outWidth和outHeight參數
        //3,根據採樣率的規則並結合目標View的所需大小計算出採樣率

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

        //4, 將BitmapFactory.Options 的 inJustDecodeBounds 的參數設置爲false,然後重新加載圖片
        options.inJustDecodeBounds = false;
        return BitmapFactory.decodeResource(res, resId, options);
    }


/**
 * TODO 從文件系統加載圖片
 * @author msh
 * @time 2016/10/22 11:15
*/
    public Bitmap decodeSampledBitmapFromFileDescriptor(FileDescriptor fd, int reqWidth, int reqHeight) {
        // First decode with inJustDecodeBounds=true to check dimensions
        final BitmapFactory.Options options = new BitmapFactory.Options();
        options.inJustDecodeBounds = true;
        BitmapFactory.decodeFileDescriptor(fd, null, options);

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

        // Decode bitmap with inSampleSize set
        options.inJustDecodeBounds = false;
        return BitmapFactory.decodeFileDescriptor(fd, null, options);
    }

    /**
     * TODO 通過計算獲取圖片的採用率 inSampleSize
     *
     * @param reqHeight ImageView的高
     * @param reqWidth  ImageView的寬
     * @author msh
     * @time 2016/10/22 11:02
     */
    public int calculateInSampleSize(BitmapFactory.Options options,
                                     int reqWidth, int reqHeight) {

        if (reqWidth == 0 || reqHeight == 0) {
            return 1;
        }
        //圖片原始的  height   width
        final int height = options.outHeight;
        final int width = options.outWidth;

        Log.d(TAG, "origin, w= " + width + " h=" + height);
        int inSampleSize = 1;

        if (height > reqHeight || width > reqWidth) {
            final int halfHeight = height / 2;
            final int halfWidth = width / 2;

            //計算最大的inSampleSize的值,
            //通過不斷的循環,最終使得圖片壓縮後的寬高都小於ImageView的寬高
            while ((halfHeight / inSampleSize) >= reqHeight && (halfWidth / inSampleSize) >= reqWidth) {
                inSampleSize *= 2;
            }
        }

        Log.d(TAG, "sampleSize:" + inSampleSize);
        return inSampleSize;
    }

}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章