2024年3月29日发(作者:奕锦文)
Android 优化Bitmap避免OutOfMemoryError
使用android提供的BitmapFactory解码图片时,往往会因为图片过大而遇到
OutOfMemoryError的异常。要想正常使用,一种简便的方式是分配更少的内存空间来存
储,即在载入图片的时候以牺牲图片质量为代价,将图片进行放缩,这是一种避免OOM所
采用的解决方法。但是,这种方法是得不偿失的,牺牲了图片质量。
在BitmapFactory中有一个内部类s,其中值得我们注意的是
inSampleSize和inJustDecodeBounds两个属性:
inSampleSize是以2的指数的倒数被进行放缩
If set to a value > 1, requests the decoder to subsample the original image,
returning a smaller image to save memory. (1 -> decodes full size; 2 -> decodes
1/4th size; 4 -> decode 1/16th size). Because you rarely need to show and
have full size bitmap images on your phone. For manipulations smaller sizes
are usually enough.
inJustDecodeBounds为Boolean型
设置inJustDecodeBounds为true后,decodeFile并不分配空间,但可计算出原始图片的
长度和宽度,即th和ght。
要对图片进行缩放,最大的问题就是怎么在运行时动态的改变inSampleSize的值,通过
上面的inJustDecodeBounds可以知道图片原始的大小,那么这样以来就可以通过算法来得
到一个恰当的inSampleSize值。其动态算法可参考下面的,网上也很多,大体都一样:
/**
* compute Sample Size
*
* @param options
* @param minSideLength
* @param maxNumOfPixels
* @return
*/
public static int computeSampleSize(s options,
int minSideLength,int maxNumOfPixels) {
int initialSize = computeInitialSampleSize(options, minSideLength,
maxNumOfPixels);
int roundedSize;
if (initialSize <=8) {
roundedSize = 1;
while (roundedSize < initialSize) {
roundedSize <<= 1;
}
} else {
roundedSize = (initialSize + 7) /8 *8;
}
return roundedSize;
}
/**
* compute Initial Sample Size
*
* @param options
* @param minSideLength
* @param maxNumOfPixels
* @return
*/
private static int computeInitialSampleSize(s options,
int minSideLength,int maxNumOfPixels) {
double w = th;
double h = ght;
// 上下限范围
int lowerBound = (maxNumOfPixels == -1) ?1 : (int) (Math
.sqrt(w * h / maxNumOfPixels));
int upperBound = (minSideLength == -1) ?128 : (int) (
(w / minSideLength), (h / minSideLength));
if (upperBound < lowerBound) {
// return the larger one when there is no overlapping zone.
return lowerBound;
}
if ((maxNumOfPixels == -1) && (minSideLength == -1)) {
return 1;
} else if (minSideLength == -1) {
return lowerBound;
} else {
return upperBound;
}
}
有了上面的算法,我们就可以轻易的get到Bitmap了:
/**
* get Bitmap
*
* @param imgFile
* @param minSideLength
* @param maxNumOfPixels
* @return
*/
public static Bitmap tryGetBitmap(String imgFile,int minSideLength,
int maxNumOfPixels) {
if (imgFile ==null || () ==0)
return null;
try {
FileDescriptor fd = new FileInputStream(imgFile).getFD();
s options = new s();
DecodeBounds = true;
// File(imgFile, options);
FileDescriptor(fd, null, options);
leSize = computeSampleSize(options, minSideLength,
maxNumOfPixels);
try {
// 这里一定要将其设置回false,因为之前我们将其设置成了true
// 设置inJustDecodeBounds为true后,decodeFile并不分配空间,即,
BitmapFactory解码出来的Bitmap为Null,但可计算出原始图片的长度和宽度
DecodeBounds = false;
Bitmap bmp = File(imgFile, options);
return bmp ==null ?null : bmp;
} catch (OutOfMemoryError err) {
return null;
}
} catch (Exception e) {
return null;
}
}
2024年3月29日发(作者:奕锦文)
Android 优化Bitmap避免OutOfMemoryError
使用android提供的BitmapFactory解码图片时,往往会因为图片过大而遇到
OutOfMemoryError的异常。要想正常使用,一种简便的方式是分配更少的内存空间来存
储,即在载入图片的时候以牺牲图片质量为代价,将图片进行放缩,这是一种避免OOM所
采用的解决方法。但是,这种方法是得不偿失的,牺牲了图片质量。
在BitmapFactory中有一个内部类s,其中值得我们注意的是
inSampleSize和inJustDecodeBounds两个属性:
inSampleSize是以2的指数的倒数被进行放缩
If set to a value > 1, requests the decoder to subsample the original image,
returning a smaller image to save memory. (1 -> decodes full size; 2 -> decodes
1/4th size; 4 -> decode 1/16th size). Because you rarely need to show and
have full size bitmap images on your phone. For manipulations smaller sizes
are usually enough.
inJustDecodeBounds为Boolean型
设置inJustDecodeBounds为true后,decodeFile并不分配空间,但可计算出原始图片的
长度和宽度,即th和ght。
要对图片进行缩放,最大的问题就是怎么在运行时动态的改变inSampleSize的值,通过
上面的inJustDecodeBounds可以知道图片原始的大小,那么这样以来就可以通过算法来得
到一个恰当的inSampleSize值。其动态算法可参考下面的,网上也很多,大体都一样:
/**
* compute Sample Size
*
* @param options
* @param minSideLength
* @param maxNumOfPixels
* @return
*/
public static int computeSampleSize(s options,
int minSideLength,int maxNumOfPixels) {
int initialSize = computeInitialSampleSize(options, minSideLength,
maxNumOfPixels);
int roundedSize;
if (initialSize <=8) {
roundedSize = 1;
while (roundedSize < initialSize) {
roundedSize <<= 1;
}
} else {
roundedSize = (initialSize + 7) /8 *8;
}
return roundedSize;
}
/**
* compute Initial Sample Size
*
* @param options
* @param minSideLength
* @param maxNumOfPixels
* @return
*/
private static int computeInitialSampleSize(s options,
int minSideLength,int maxNumOfPixels) {
double w = th;
double h = ght;
// 上下限范围
int lowerBound = (maxNumOfPixels == -1) ?1 : (int) (Math
.sqrt(w * h / maxNumOfPixels));
int upperBound = (minSideLength == -1) ?128 : (int) (
(w / minSideLength), (h / minSideLength));
if (upperBound < lowerBound) {
// return the larger one when there is no overlapping zone.
return lowerBound;
}
if ((maxNumOfPixels == -1) && (minSideLength == -1)) {
return 1;
} else if (minSideLength == -1) {
return lowerBound;
} else {
return upperBound;
}
}
有了上面的算法,我们就可以轻易的get到Bitmap了:
/**
* get Bitmap
*
* @param imgFile
* @param minSideLength
* @param maxNumOfPixels
* @return
*/
public static Bitmap tryGetBitmap(String imgFile,int minSideLength,
int maxNumOfPixels) {
if (imgFile ==null || () ==0)
return null;
try {
FileDescriptor fd = new FileInputStream(imgFile).getFD();
s options = new s();
DecodeBounds = true;
// File(imgFile, options);
FileDescriptor(fd, null, options);
leSize = computeSampleSize(options, minSideLength,
maxNumOfPixels);
try {
// 这里一定要将其设置回false,因为之前我们将其设置成了true
// 设置inJustDecodeBounds为true后,decodeFile并不分配空间,即,
BitmapFactory解码出来的Bitmap为Null,但可计算出原始图片的长度和宽度
DecodeBounds = false;
Bitmap bmp = File(imgFile, options);
return bmp ==null ?null : bmp;
} catch (OutOfMemoryError err) {
return null;
}
} catch (Exception e) {
return null;
}
}