您的位置:首页 > 移动开发 > Android开发

android BitmapFactory的OutOfMemoryError: bitmap size exceeds VM budget解决方案

2011-08-24 13:12 381 查看
转自:/article/5641917.html

使用android提供的BitmapFactory解码一张图片时,有时会遇到该错误,即:java.lang.OutOfMemoryError:bitmapsizeexceedsVMbudget。这往往是由于图片过大造成的。要想正常使用,一种方式是分配更少的内存空间来存储,即在载入图片的时候以牺牲图片质量为代价,将图片进行放缩,这也是不少人现在为避免以上的OOM所采用的解决方法。但是,这种方法是得不偿失的,当我们使用图片作为缩略图查看时候倒是没有说什么,但是,当需要提供图片质量的时候,该怎么办呢?java.lang.OutOfMemoryError:
bitmapsizeexceedsVMbudget着实让不少人欲哭无泪呀!前几天刚好有个需求需要载入SD卡上面的图片。

首先是使用

viewsourceprint?

Bitmapbmp=BitmapFactory.decodeFile(pePicFile.getAbsolutePath()+
"/"
+info.getImage());
上面参数是我将要读取的图片文件及路径,当文件较小时,程序能够正常运行,但是当我选择一张大图时,程序立刻蹦出了java.lang.OutOfMemoryError:bitmapsizeexceedsVMbudget的OOM错误!

在android设备上(whereyouhaveonly16MBmemoryavailable),如果使用BitmapFactory解码一个较大文件,很大的情况下会出现上述情况。那么,怎么解决?!

先说之前提到过的一种方法:即将载入的图片缩小,这种方式以牺牲图片的质量为代价。在BitmapFactory中有一个内部类BitmapFactory.Options,其中当options.inSampleSize值>1时,根据文档:

Ifsettoavalue>1,requeststhedecodertosubsampletheoriginalimage,returningasmallerimagetosavememory.(1->decodesfullsize;2->decodes1/4thsize;4->decode1/16thsize).Becauseyourarelyneedtoshowandhavefullsizebitmapimagesonyourphone.Formanipulationssmallersizesareusuallyenough.

也就是说,options.inSampleSize是以2的指数的倒数被进行放缩。这样,我们可以依靠inSampleSize的值的设定将图片放缩载入,这样一般情况也就不会出现上述的OOM问题了。现在问题是怎么确定inSampleSize的值?每张图片的放缩大小的比例应该是不一样的!这样的话就要运行时动态确定。在BitmapFactory.Options中提供了另一个成员inJustDecodeBounds。

viewsourceprint?

1
BitmapFactory.Optionsopts=

new
BitmapFactory.Options();
2
opts.inJustDecodeBounds=
true
;
3
Bitmapbitmap=BitmapFactory.decodeFile(imageFile,opts);
设置inJustDecodeBounds为true后,decodeFile并不分配空间,但可计算出原始图片的长度和宽度,即opts.width和opts.height。有了这两个参数,再通过一定的算法,即可得到一个恰当的inSampleSize。Android提供了一种动态计算的方法。如下:

viewsourceprint?

01
public
static
int
computeSampleSize(BitmapFactory.Optionsoptions,
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.Optionsoptions,
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
}
以上参考一下,我们只需要使用此函数就行了:

viewsourceprint?

BitmapFactory.Optionsopts=

new
BitmapFactory.Options();
opts.inJustDecodeBounds=
true
;
BitmapFactory.decodeFile(imageFile,opts);
opts.inSampleSize=computeSampleSize(opts,-
1
,
128
*
128
);
//这里一定要将其设置回false,因为之前我们将其设置成了true
opts.inJustDecodeBounds=
false
;
try

{
Bitmapbmp=BitmapFactory.decodeFile(imageFile,opts);
imageView.setImageBitmap(bmp);
}

catch
(OutOfMemoryErrorerr){
}
这样,在BitmapFactory.decodeFile执行处,也就不会报出上面的OOMError了。完美解决?如前面提到的,这种方式在一定程度上是以牺牲图片质量为代价的。如何才能更加优化的实现需求?

当在android设备中载入较大图片资源时,可以创建一些临时空间,将载入的资源载入到临时空间中。

viewsourceprint?

1
BitmapFactory.OptionsbfOptions=
new

BitmapFactory.Options();
2
bfOptions.inTempStorage=
new

byte
[
12

*
1024
];
以上创建了一个12kb的临时空间。然后使用BitmapbitmapImage=BitmapFactory.decodeFile(path,bfOptions);但是我在程序中却还是出现以上问题!以下使用BitmapFactory.decodeFileDescriptor解决了以上问题:

viewsourceprint?

01
BitmapFactory.OptionsbfOptions=
new

BitmapFactory.Options();
02
bfOptions.inDither=
false
;
03
bfOptions.inPurgeable=
true
;
04
bfOptions.inTempStorage=
new

byte
[
12

*
1024
];
05
//bfOptions.inJustDecodeBounds=true;
06
Filefile=
new
File(pePicFile.getAbsolutePath()+
"/"
+info.getImage());
07
FileInputStreamfs=
null
;
08
try

{
09
fs=
new
FileInputStream(file);
10
}
catch
(FileNotFoundExceptione){
11
e.printStackTrace();
12
}
13
Bitmapbmp=
null
;
14
if
(fs!=
null
)
15
try

{
16
bmp=BitmapFactory.decodeFileDescriptor(fs.getFD(),
null
,bfOptions);
17
}
catch
(IOExceptione){
18
e.printStackTrace();
19
}
finally
{
20
if
(fs!=
null
){
21
try

{
22
fs.close();
23
}
catch
(IOExceptione){
24
e.printStackTrace();
25
}
26
}
27
}
当然要将取得图片进行放缩显示等处理也可以在以上得到的bmp进行。

PS:请图片处理后进行内存回收。bmp.recycle();这样将图片占有的内存资源释放。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐