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

Android BitmapFactory的OutOfMemoryError问题,最近看到

2012-11-16 16:33 387 查看
关于OutOfMemoryError问题,偶尔出现,还是得去解决一下,最近看到个不错的解决方式:来自于:/article/3555123.html常用一种解决方法:即将载入的图片缩小,这种方式以牺牲图片的质量为代价。在BitmapFactory中有一个内部类BitmapFactory.Options,其中当options.inSampleSize值>1时,根据文档:Ifsettoavalue>1,requeststhedecodertosubsampletheoriginalimage,returningasmallerimagetosavememory.(1->decodesfullsize;2->decodes1/4thsize;4->decode1/16thsize).Becauseyourarelyneedtoshowandhavefullsizebitmapimagesonyourphone.Formanipulationssmallersizesareusuallyenough.options.inSampleSize是以2的指数的倒数被进行放缩现在问题是怎么确定inSampleSize的值?每张图片的放缩大小的比例应该是不一样的!这样的话就要运行时动态确定。在BitmapFactory.Options中提供了另一个成员inJustDecodeBounds。设置inJustDecodeBounds为true后,decodeFile并不分配空间,但可计算出原始图片的长度和宽度,即opts.width和opts.height。有了这两个参数,再通过一定的算法,即可得到一个恰当的inSampleSize。Android提供了一种动态计算的方法,见computeSampleSize().
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
}
以上只做为参考,我们只要用这函数即可,
opts.inSampleSize=computeSampleSize(opts,-
1
,
128
*
128
);
要点:1、用decodeFileDescriptor()来生成bimap比decodeFile()省内存
1
FileInputStreamis==
new
FileInputStream(path);
2
bmp=BitmapFactory.decodeFileDescriptor(is.getFD(),
null
,opts);
替换
1
Bitmapbmp=BitmapFactory.decodeFile(imageFile,opts);
2
imageView.setImageBitmap(bmp);
原因:查看BitmapFactory的源码,对比一下两者的实现,可以发现decodeFile()最终是以流的方式生成bitmapdecodeFile源码:
01
public
static
BitmapdecodeFile(StringpathName,Optionsopts){
02
Bitmapbm=
null
;
03
InputStreamstream=
null
;
04
try
{
05
stream=
new
FileInputStream(pathName);
06
bm=decodeStream(stream,
null
,opts);
07
}
catch
(Exceptione){
08
/*donothing.
09
Iftheexceptionhappenedonopen,bmwillbenull.
10
*/
11
}
finally
{
12
if
(stream!=
null
){
13
try
{
14
stream.close();
15
}
catch
(IOExceptione){
16
//donothinghere
17
}
18
}
19
}
20
return
bm;
21
}
decodeFileDescriptor的源码,可以找到native本地方法decodeFileDescriptor,通过底层生成bitmapdecodeFileDescriptor源码:
01
public
static
BitmapdecodeFileDescriptor(FileDescriptorfd,RectoutPadding,Optionsopts){
02
if
(nativeIsSeekable(fd)){
03
Bitmapbm=nativeDecodeFileDescriptor(fd,outPadding,opts);
04
if
(bm==
null
&&opts!=
null
&&opts.inBitmap!=
null
){
05
throw
new
IllegalArgumentException(
"Problemdecodingintoexistingbitmap"
);
06
}
07
return
finishDecode(bm,outPadding,opts);
08
}
else
{
09
FileInputStreamfis=
new
FileInputStream(fd);
10
try
{
11
return
decodeStream(fis,outPadding,opts);
12
}
finally
{
13
try
{
14
fis.close();
15
}
catch
(Throwablet){
/*ignore*/
}
16
}
17
}
18
}
19
20
private
static
native
BitmapnativeDecodeFileDescriptor(FileDescriptorfd,Rectpadding,Optionsopts);
2、当在android设备中载入较大图片资源时,可以创建一些临时空间,将载入的资源载入到临时空间中。
1
opts.inTempStorage=
new
byte
[
16
*
1024
];
?完整代码:viewsourceprint?
01
public
static
OutputStreamdecodeBitmap(Stringpath){
02
03
BitmapFactory.Optionsopts=
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
FileInputStreamis=
null
;
15
Bitmapbmp=
null
;
16
InputStreamins=
null
;
17
ByteArrayOutputStreambaos=
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
Bitmapbmp2=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
(FileNotFoundExceptione){
30
e.printStackTrace();
31
}
catch
(IOExceptione){
32
e.printStackTrace();
33
}
finally
{
34
try
{
35
is.close();
36
ins.close();
37
baos.close();
38
}
catch
(IOExceptione){
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
}
==============================================================================================================以上来自于转载:接下来来点自己的这块写的代码:/***根据filename获取bitmap**@paramheight*@paramwidth*/publicstaticBitmapgetBitmapByName(Stringfilename,intwidth,intheight){Bitmapbitmap=null;if(!hasSDcard()){returnbitmap;}Filefile=newFile(filename);FileInputStreamfs=null;try{fs=newFileInputStream(file);}catch(FileNotFoundExceptione){e.printStackTrace();}if(!file.exists()||!file.isFile()){returnbitmap;}try{Bitmapbmp=null;Optionsopts=newBitmapFactory.Options();opts.inJustDecodeBounds=true;bmp=BitmapFactory.decodeFile(file.getPath(),opts);//计算图片缩放比例finalintminSideLength=Math.min(width,height);opts.inSampleSize=computeSampleSize(opts,minSideLength,width*height);opts.inJustDecodeBounds=false;opts.inInputShareable=true;opts.inPurgeable=true;opts.inDither=false;opts.inPurgeable=true;opts.inTempStorage=newbyte[16*1024];//bitmap=BitmapFactory.decodeFile(file.getPath(),opts);if(fs!=null){bmp=BitmapFactory.decodeFileDescriptor(fs.getFD(),null,opts);bitmap=Bitmap.createBitmap(bmp);}//---将图片占有的内存资源释放bmp=null;//bmp.recycle();//这里的回收,在程序里有点问题System.gc();}catch(Exceptione){//TODOAuto-generatedcatchblockLog.e("getbitmap","exception");e.printStackTrace();bitmap=null;}finally{if(fs!=null){try{fs.close();}catch(IOExceptione){e.printStackTrace();}}}returnbitmap;}//--------------------------------------/***计算缩放的比例***/privatestaticintcomputeSampleSize(BitmapFactory.Optionsoptions,intminSideLength,intmaxNumOfPixels){intinitialSize=computeInitialSampleSize(options,minSideLength,maxNumOfPixels);introundedSize;if(initialSize<=8){roundedSize=1;while(roundedSize<initialSize){roundedSize<<=1;}}else{roundedSize=(initialSize+7)/8*8;}returnroundedSize;}privatestaticintcomputeInitialSampleSize(BitmapFactory.Optionsoptions,intminSideLength,intmaxNumOfPixels){doublew=options.outWidth;doubleh=options.outHeight;intlowerBound=(maxNumOfPixels==-1)?1:(int)Math.ceil(Math.sqrt(w*h/maxNumOfPixels));intupperBound=(minSideLength==-1)?128:(int)Math.min(Math.floor(w/minSideLength),Math.floor(h/minSideLength));if(upperBound<lowerBound){//returnthelargeronewhenthereisnooverlappingzone.returnlowerBound;}if((maxNumOfPixels==-1)&&(minSideLength==-1)){return1;}elseif(minSideLength==-1){returnlowerBound;}else{returnupperBound;}}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐