android BitmapFactory的OutOfMemoryError: bitmap ...
来源:互联网 发布:php 正则验证身份证号 编辑:程序博客网 时间:2024/06/07 11:23
原文地址:http://my.oschina.net/jeffzhao/blog/80900
网上有很多解决android加载bitmap内存溢出的方法,搜了一圈做下整理总结。项目里需求是拍摄多图之后上传,部分手机会内存溢出。
常用一种解决方法:即将载入的图片缩小,这种方式以牺牲图片的质量为代价。在BitmapFactory中有一个内部类BitmapFactory.Options,其中当options.inSampleSize值>1时,根据文档:
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.
options.inSampleSize是以2的指数的倒数被进行放缩
现在问题是怎么确定inSampleSize的值?每张图片的放缩大小的比例应该是不一样的!这样的话就要运行时动态确定。在BitmapFactory.Options中提供了另一个成员inJustDecodeBounds。
设置inJustDecodeBounds为true后,decodeFile并不分配空间,但可计算出原始图片的长度和宽度,即opts.width和opts.height。有了这两个参数,再通过一定的算法,即可得到一个恰当的inSampleSize。Android提供了一种动态计算的方法,见computeSampleSize().
01
public
static
int
computeSampleSize(BitmapFactory.Options options,
02
int
minSideLength,
int
maxNumOfPixels) {
03
int
initialSize = computeInitialSampleSize(options, minSideLength,
04
maxNumOfPixels);
05
06
int
roundedSize;
07
if
(initialSize <=
8
) {
08
roundedSize =
1
;
09
while
(roundedSize < initialSize) {
10
roundedSize <<=
1
;
11
}
12
}
else
{
13
roundedSize = (initialSize +
7
) /
8
*
8
;
14
}
15
16
return
roundedSize;
17
}
18
19
private
static
int
computeInitialSampleSize(BitmapFactory.Options options,
20
int
minSideLength,
int
maxNumOfPixels) {
21
double
w = options.outWidth;
22
double
h = options.outHeight;
23
24
int
lowerBound = (maxNumOfPixels == -
1
) ?
1
:
25
(
int
) Math.ceil(Math.sqrt(w * h / maxNumOfPixels));
26
int
upperBound = (minSideLength == -
1
) ?
128
:
27
(
int
) Math.min(Math.floor(w / minSideLength),
28
Math.floor(h / minSideLength));
29
30
if
(upperBound < lowerBound) {
31
return
lowerBound;
32
}
33
34
if
((maxNumOfPixels == -
1
) &&
35
(minSideLength == -
1
)) {
36
return
1
;
37
}
else
if
(minSideLength == -
1
) {
38
return
lowerBound;
39
}
else
{
40
return
upperBound;
41
}
42
}
以上只做为参考,我们只要用这函数即可,opts.inSampleSize = computeSampleSize(opts, -
1
,
128
*
128
);
要点:
1、用decodeFileDescriptor()来生成bimap比decodeFile()省内存
1
FileInputStream is = =
new
FileInputStream(path);
2
bmp = BitmapFactory.decodeFileDescriptor(is.getFD(),
null
, opts);
替换
1
Bitmap bmp = BitmapFactory.decodeFile(imageFile, opts);
2
imageView.setImageBitmap(bmp);
原因:
查看BitmapFactory的源码,对比一下两者的实现,可以发现decodeFile()最终是以流的方式生成bitmap
decodeFile源码:
01
public
static
Bitmap decodeFile(String pathName, Options opts) {
02
Bitmap bm =
null
;
03
InputStream stream =
null
;
04
try
{
05
stream =
new
FileInputStream(pathName);
06
bm = decodeStream(stream,
null
, opts);
07
}
catch
(Exception e) {
08
/* do nothing.
09
If the exception happened on open, bm will be null.
10
*/
11
}
finally
{
12
if
(stream !=
null
) {
13
try
{
14
stream.close();
15
}
catch
(IOException e) {
16
// do nothing here
17
}
18
}
19
}
20
return
bm;
21
}
decodeFileDescriptor的源码,可以找到native本地方法decodeFileDescriptor,通过底层生成bitmap
decodeFileDescriptor源码:
01
public
static
Bitmap decodeFileDescriptor(FileDescriptor fd, Rect outPadding, Options opts) {
02
if
(nativeIsSeekable(fd)) {
03
Bitmap bm = nativeDecodeFileDescriptor(fd, outPadding, opts);
04
if
(bm ==
null
&& opts !=
null
&& opts.inBitmap !=
null
) {
05
throw
new
IllegalArgumentException(
"Problem decoding into existing bitmap"
);
06
}
07
return
finishDecode(bm, outPadding, opts);
08
}
else
{
09
FileInputStream fis =
new
FileInputStream(fd);
10
try
{
11
return
decodeStream(fis, outPadding, opts);
12
}
finally
{
13
try
{
14
fis.close();
15
}
catch
(Throwable t) {
/* ignore */
}
16
}
17
}
18
}
19
20
private
static
native
Bitmap nativeDecodeFileDescriptor(FileDescriptor fd,Rect padding, Options opts);
2、当在android设备中载入较大图片资源时,可以创建一些临时空间,将载入的资源载入到临时空间中。
1
opts.inTempStorage =
new
byte
[
16
*
1024
];
完整代码:
01
public
static
OutputStream decodeBitmap(String path) {
02
03
BitmapFactory.Options opts =
new
BitmapFactory.Options();
04
opts.inJustDecodeBounds =
true
;
// 设置成了true,不占用内存,只获取bitmap宽高
05
BitmapFactory.decodeFile(path, opts);
06
opts.inSampleSize = computeSampleSize(opts, -
1
,
1024
*
800
);
07
08
opts.inJustDecodeBounds =
false
;
// 这里一定要将其设置回false,因为之前我们将其设置成了true
09
opts.inPurgeable =
true
;
10
opts.inInputShareable =
true
;
11
opts.inDither =
false
;
12
opts.inPurgeable =
true
;
13
opts.inTempStorage =
new
byte
[
16
*
1024
];
14
FileInputStream is =
null
;
15
Bitmap bmp =
null
;
16
InputStream ins =
null
;
17
ByteArrayOutputStream baos =
null
;
18
try
{
19
is =
new
FileInputStream(path);
20
bmp = BitmapFactory.decodeFileDescriptor(is.getFD(),
null
, opts);
double
scale = getScaling(opts.outWidth * opts.outHeight,
1024
*
600
);
21
Bitmap bmp2 = Bitmap.createScaledBitmap(bmp,
22
(
int
) (opts.outWidth * scale),
23
(
int
) (opts.outHeight * scale),
true
);
24
bmp.recycle();
25
baos =
new
ByteArrayOutputStream();
26
bmp2.compress(Bitmap.CompressFormat.JPEG,
100
, baos);
27
bmp2.recycle();
28
return
baos;
29
}
catch
(FileNotFoundException e) {
30
e.printStackTrace();
31
}
catch
(IOException e) {
32
e.printStackTrace();
33
}
finally
{
34
try
{
35
is.close();
36
ins.close();
37
baos.close();
38
}
catch
(IOException e) {
39
e.printStackTrace();
40
}
41
System.gc();
42
}
43
return
baos;
44
}
45
46
private
static
double
getScaling(
int
src,
int
des) {
47
/**
48
* 目标尺寸÷原尺寸 sqrt开方,得出宽高百分比
49
*/
50
double
scale = Math.sqrt((
double
) des / (
double
) src);
51
return
scale;
52
}
- android BitmapFactory的OutOfMemoryError: bitmap ...
- android BitmapFactory的OutOfMemoryError: bitmap size exceeds VM budget解决方案
- android BitmapFactory的OutOfMemoryError: bitmap size exceeds VM budget解决方案
- android BitmapFactory的OutOfMemoryError: bitmap size exceeds VM budget解决方案
- android BitmapFactory的OutOfMemoryError: bitmap size exceeds VM budget解决..
- android BitmapFactory的OutOfMemoryError: bitmap size exceeds VM budget解决方案
- android BitmapFactory的OutOfMemoryError: bitmap size exceeds VM budget解决方案
- android BitmapFactory的OutOfMemoryError: bitmap size exceeds VM budget解决方案
- android BitmapFactory的OutOfMemoryError: bitmap size exceeds VM budget解决方案
- android BitmapFactory的OutOfMemoryError: bitmap size exceeds VM budget解决方案
- android BitmapFactory的OutOfMemoryError: bitmap size exceeds VM budget解决方案
- android BitmapFactory的OutOfMemoryError: bitmap size exceeds VM budget解决方案
- android BitmapFactory的OutOfMemoryError 解决
- Android BitmapFactory的OutOfMemoryError问题,最近看到
- Android图片之Bitmap、BitmapFactory
- android的Bitmap和BitmapFactory类的使用
- 关于android缩放bitmap,BitmapFactory.Options.inSampleSize的优化算法
- Android——Bitmap及其BitmapFactory的常用方法
- Ext的extend继承
- snmp开发记录2--使用python扩展
- 1062: 人见人爱A-B
- OracleADF学习之道之经验
- oracle下载账号
- android BitmapFactory的OutOfMemoryError: bitmap ...
- 忘记weblogic控制台密码解决办法
- memcached的基本命令(安装、卸载、启动、配置相关)
- Datatable的Select()方法简介
- 使用TCMalloc可选择使用内存分配程序
- [ios专项]ios socket 之常规socket以及第三方开源类库AsyncSocket
- MySQL数据库使用中需要注意的的23点
- 当前程序暂停 & 线程暂停
- 见或不见