有效解决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官方的介绍:

这个已经非常的明白了,我们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() //提醒系统及时回收
}

有效解决Android加载大图片时内存溢出的问题,布布扣,bubuko.com

时间: 2024-10-25 18:17:36

有效解决Android加载大图片时内存溢出的问题的相关文章

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

Android有效解决加载大图片时内存溢出的问题 博客分类: Android Android游戏虚拟机算法JNI 尽量不要使用setImageBitmap或setImageResource或BitmapFactory.decodeResource来设置一张大图,因为这些函数在完成decode后,最终都是通过java层的createBitmap来完成的,需要消耗更多内存. 因此,改用先通过BitmapFactory.decodeStream方法,创建出一个bitmap,再将其设为ImageView

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

尽量不要使用setImageBitmap或setImageResource或BitmapFactory.decodeResource来设置一张大图, 因为这些函数在完成decode后,最终都是通过java层的createBitmap来完成的,需要消耗更多内存. 因此,改用先通过BitmapFactory.decodeStream方法,创建出一个bitmap,再将其设为ImageView的 source, decodeStream最大的秘密在于其直接调用JNI>>nativeDecodeAsse

Android加载大图片到内存

加载大图片到内存 步骤: 步骤一: 获取品屏幕的宽高数据;[HD1] 步骤二: 获取图片的宽高;[HD2] 步骤三: 计算屏幕与图片的宽高比例,按照差距最大的进行缩放处理;[HD3] 步骤四: 图片的缩放处理;[HD4] [HD1]// 获取手机的屏幕的窗体大小 WindowManager windowManager = (WindowManager) getSystemService(WINDOW_SERVICE); Display display = windowManager.getDef

[android] 加载大图片到内存

默认情况下,android程序分配的堆内存大小是16,虚拟机上面的VM Heep就是设置它的 一个图片所占的内存,比如1920*2560像素的图片需要,1920*2560*3至少这些的内存byte 找到ImageView控件对象 调用BitmapFactory对象的decodeFile(pathName)方法,来获取一个位图对象,参数:pathName是String类型的图片路径 把图片导入到手机的sdcard目录下面 调用ImageView对象的setImageBitmap(bitemap)方

Android加载大图片(压缩)

转载自http://blog.csdn.net/junjx/article/details/7798604 在Android开发中,我们经常需要加载图片.但是图片的尺寸往往会很大,如果我们要的是比较小的图片,在Android有限的内存下,我们显然不能把大尺寸的图片放到内存里,这样不但效率降低,而且会导致java.lang.OutOfMemory异常,相信很多朋友都遇到过这样的问题,那么该怎么解决这一问题呢?其实在Android官方文档中早已给出了解决的方案. 一.读Bitmap的尺寸和类型   

Android -- 加载大图片的方法

在android中要加载一张大图片到内存中如果通过如下方式进行: Bitmap bitmap= BitmapFactory.decodeFile("/sdcard/a.jpg"); iv.setImageBitmap(bitmap); 则会抛出内存溢出异常Caused by: java.lang.OutOfMemoryError 正确的做法应该是这样的: public class MainActivity extends Activity { private ImageView iv;

Android(java)学习笔记236:多媒体之加载大图片到内存(Bitmap API)

1.Bitmap (API使用) android里面的bitmap中,一个像素点需要4个byte去表示,这是因为android表示颜色是" argb ":其中 a 表示是透明度,然后是" rgb" 颜色表示范围 00000000 ~~~ffffffff 2.加载图片到内存: 上面说到了图形表示使用4byte,和int一样,所以Android里面每个像素点都是使用一个int来表示的. Bitmap bitmap = BitmapFactory.decodeResour

Android加载大图片OOM异常解决

尽量不要使用setImageBitmap或setImageResource或BitmapFactory.decodeResource来设置一张大图, 因为这些函数在完成decode后,最终都是通过java层的createBitmap来完成的,需要消耗更多内存. 因此,改用先通过BitmapFactory.decodeStream方法,创建出一个bitmap,再将其设为ImageView的 source, decodeStream最大的秘密在于其直接调用JNI>>nativeDecodeAsse

缩放图片加载大图片

> 图片大小 = 图片的总像素 * 每个像素占用的大小 * 单色图:每个像素占用1/8个字节 * 16色图:每个像素占用1/2个字节 * 256色图:每个像素占用1个字节 * 24位图:每个像素占用3个字节 --- #加载大图片到内存(掌握) >Android系统以ARGB表示每个像素,所以每个像素占用4个字节,很容易内存溢出 ##对图片进行缩放(掌握) *第一步:获取屏幕宽高 Display dp = getWindowManager().getDefaultDisplay(); int s