首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > 移动开发 > Android >

有效解决Android加载大图片时内存溢出的有关问题[转]

2013-07-04 
有效解决Android加载大图片时内存溢出的问题[转]?首先解析一下基本的知识:位图模式,bitmap颜色位数是1位灰

有效解决Android加载大图片时内存溢出的问题[转]

?

首先解析一下基本的知识:

位图模式,bitmap颜色位数是1位

灰度模式,bitmap颜色位数是8位,和256色一样

?

RGB模式,bitmap颜色位数是24位?在RGB模式下,一个像素对应的是红、绿、蓝三个字节

CMYK模式,bitmap颜色位数是32位??在CMYK模式下,一个像素对应的是青、品、黄、黑四个字节

图像文件的字节数(Byte) = 图像分辨率*颜色深度/8(bit/8)

例如:一幅640*480图像分辨率、RGB色一般为24位真彩色,图像未经压缩的数据容量为:640X480X24/8=921600字节=900KB(1KB=l千字节=1024字节)。
注: 一个图像文件占的磁盘空间大小还和磁盘的文件格式有关。如:NTFS最小单位为4KB?所以图像文件大小肯定是4KB的倍数。但是有图图片压缩算法的存 在,图片文件在保存时,体积要比在内存的大小小得多,如640x480的图片文件大小一般只在200K~300K。这也是为什么,加载几MB的图片文件, 会导致JVM内存溢出,导致OutofMemoryException的原因。

?

由上面的公式,我们可以得出,加载的图片所占的内存大小,取决于其分辨率和颜色数

?

我们再来看看Google官方的介绍:

?

有效解决Android加载大图片时内存溢出的有关问题[转]

这个已经非常的明白了,我们VM的app进程所获得的内存只有区区的16MB,普普通通的5MP摄像头拍出来的图片,直接加载,将占用接近19MB的内存。可见,不进行压缩,内存将会直接溢出。

?

再了解一下,android读取解析图片的方式,基本与Java的方式类型,通过文件输入流,然后进行解码,再转成图片格式;

?

当然google的 android也为我们封装好了若干方法,来方便快捷地完成这项工作,如ImageView的 setImageBitmap,setImageResource,BitmapFactory的decodeResource等,但是尽量不要使用 setImageBitmap或setImageResource或BitmapFactory.decodeResource来设置一张大图,因为这些 函数在完成decode后,最终都是通过java层的createBitmap来完成的,需要消耗更多内存;

?

因此,改用先通过 BitmapFactory.decodeStream方法,创建出一个bitmap,再将其设为ImageView的source,加载显示。 decodeStream最大的秘密在于其直接调用JNI>>nativeDecodeAsset()来完成decode,无需再使用 java层的createBitmap,从而节省了java层的空间。

?

在使用decodeStream读取图片时,再加上Config参数,就可以更有效地控制加载目标的内存大小,从而更有效阻止抛OutofMemoryException异常,下面用一段代码说明: public static Bitmap readBitmapAutoSize(String filePath, int outWidth, int outHeight) { //outWidth和outHeight是目标图片的最大宽度和高度,用作限制 FileInputStream fs = null; BufferedInputStream bs = null; try { fs = new FileInputStream(filePath); bs = new BufferedInputStream(fs); BitmapFactory.Options options = setBitmapOption(filePath, outWidth, outHeight); return BitmapFactory.decodeStream(bs, null, options); } catch (Exception e) { e.printStackTrace(); } finally { try { bs.close(); fs.close(); } catch (Exception e) { e.printStackTrace(); } } return null; } private static BitmapFactory.Options setBitmapOption(String file, int width, int height) { BitmapFactory.Options opt = new BitmapFactory.Options(); opt.inJustDecodeBounds = true; //设置只是解码图片的边距,此操作目的是度量图片的实际宽度和高度 BitmapFactory.decodeFile(file, opt); int outWidth = opt.outWidth; //获得图片的实际高和宽 int outHeight = opt.outHeight; opt.inDither = false; opt.inPreferredConfig = Bitmap.Config.RGB_565; //设置加载图片的颜色数为16bit,默认是RGB_8888,表示24bit颜色和透明通道,但一般用不上 opt.inSampleSize = 1; //设置缩放比,1表示原比例,2表示原来的四分之一.... //计算缩放比 if (outWidth != 0 && outHeight != 0 && width != 0 && height != 0) { int sampleSize = (outWidth / width + outHeight / height) / 2; opt.inSampleSize = sampleSize; } opt.inJustDecodeBounds = false;//最后把标志复原 return opt; } ?另 外,decodeStream直接拿的图片来读取字节码了,?不会根据机器的各种分辨率来自动适应,?使用了decodeStream之后,需要在 hdpi和mdpi,ldpi中配置相应的图片资源,?否则在不同分辨率机器上都是同样大小(像素点数量),显示出来的大小就不对了。 可参考下面的代码:
BitmapFactory.Options opts = new BitmapFactory.Options();  //设置图片的DPI为当前手机的屏幕dpi  opts.inTargetDensity = ctx.getResources().getDisplayMetrics().densityDpi;    opts.inScaled = true; 
?另外,图片的bitmap对象为大对象,不用了要注意主动回收,
    if(!bmp.isRecycle() ){              bmp.recycle()   //回收图片所占的内存              system.gc()  //提醒系统及时回收   
?

热点排行