Bitmap 的加載和Cache
Bitmap的高效加載(圖片的壓縮)
OOM
由於Bitmap的特殊性以及Android對單個應用所施加的內存限制,比如16M這導致加載Bitmap的時候很容易就出現內存溢出.
java.lang.OutofMemoryError:bitmap size exceeds VM budget
所以我們需要多圖片進行壓縮,這樣就不會佔用多餘的內存空間.
如何加載一張圖片
Bitmap在Android中指的是一張圖片,比如JGP,PNG,以及其他的格式的圖片.
BitmapFactory 類提供了四類方法,
- decodeFile 文件系統
- decodeResource 資源
- decodeStream 輸入流
- decodeByteArray 字節數組
如何高效的加載一張圖片呢
核心思想就是,採用BimapFactory.Options來加載圖片所需的尺寸的圖片. 將縮小後的圖片在ImageView中顯示,這樣就降低內存佔用率,從而一定程度上避免OOM
BitmapFactory.Options 主要用到了inSampleSize(採用率)
- inSampleSize==1 原圖顯示
inSampleSize==2 寬高爲原來的1/2 , 圖片爲原來的1/4
inSmpleSize 只能是1,2,4,8,16, 2的指數,如果不是的話就去最接近2的指數的數值.
如何獲取採用率?
- 將BitmapFactory.Options的inJustDecodeBounds參數設爲true並加載圖片
- 從BitmapFactory.Options中取出圖片的原始寬高信息,他們對應於outWidth和outHeight參數
- 根據採樣率的規則並結合目標View的所需大小計算出採樣率
- 將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;
}
}