情景再现
今天写了两个东西,一个是通过照相机拍摄照片,然后获得照片之后将它设置到 ImageView 上面,另一个是通过相册,或者文件获得照片,放到 ImageView 上面。
一开始,一切正常
然后我做了下面的操作:
点击拍照,将拍到的照片放到了 ImageView 上面,然后我又点击拍照,在放到 ImageView 上面的时候崩溃了。OutOfMemory
我的代码是这样写的:
- 点击按钮的操作
- Intent i = new Intent(Intent.ACTION_GET_CONTENT);
- i.setType("image/*");
- startActivityForResult(i, 1);
- onActivityResult 里面
- Uri uri = data.getData();
- mBitmap = getBitmapFromUri(uri);
- iv.setImageBitmap(mBitmap);//iv 是 ImageView 的
- getBitmapFromUri 中的代码:
- Bitmap bitmap = MediaStore.Images.Media.getBitmap(this.getContentResolver(), uri);
- return bitmap;
程序崩溃在了 getBitmap(this.getContentResolver(), uri)。
然后我打开了 getBitmap 方法,里面的代码是这样的:
- public static final Bitmap getBitmap(ContentResolver cr, Uri url) throws FileNotFoundException, IOException {
- InputStream input = cr.openInputStream(url);
- Bitmap bitmap = BitmapFactory.decodeStream(input);
- input.close();
- return bitmap;
- }
它直接调用了 decodeStream(input)。
经过总结发现,估计是因为 G3 手机拍摄相片分辨率过高,使图片过大,造成过程中内存溢出,通过网上搜索若干解决加载大图片时内存溢出的问题:
尽量不要使用 setImageBitmap 或 setImageResource 或 BitmapFactory.decodeResource 来设置一张大图,因为这些函数在完成 decode 后,最终都是通过 java 层的 createBitmap 来完成的,需要消耗更多内存。
解决办法
只修改了一个地方,就是 getBitmap 中的 decodeStream 的调用。
下面是修改后的 getBitmapFromUri 方法:
- private Bitmap getBitmapFromUri(Uri uri) {
- try {
- // 读取 uri 所在的图片
- // Bitmap bitmap = MediaStore.Images.Media.getBitmap(this.getContentResolver(), uri);
- InputStream input = this.getContentResolver().openInputStream(uri);
- BitmapFactory.Options opts=new BitmapFactory.Options();
- opts.inTempStorage = new byte[100 * 1024];
- //3. 设置位图颜色显示优化方式
- //ALPHA_8:每个像素占用 1byte 内存(8 位)
- //ARGB_4444: 每个像素占用 2byte 内存(16 位)
- //ARGB_8888: 每个像素占用 4byte 内存(32 位)
- //RGB_565: 每个像素占用 2byte 内存(16 位)
- //Android 默认的颜色模式为 ARGB_8888,这个颜色模式色彩最细腻,显示质量最高。但同样的,占用的内存//也最大。也就意味着一个像素点占用 4 个字节的内存。我们来做一个简单的计算题:3200*2400*4 bytes //=30M。如此惊人的数字!哪怕生命周期超不过 10s,Android 也不会答应的。
- opts.inPreferredConfig = Bitmap.Config.RGB_565;
- //4. 设置图片可以被回收,创建 Bitmap 用于存储 Pixel 的内存空间在系统内存不足时可以被回收
- opts.inPurgeable = true;
- //5. 设置位图缩放比例
- //width,hight 设为原来的四分一(该参数请使用 2 的整数倍), 这也减小了位图占用的内存大小;例如,一张//分辨率为 2048*1536px 的图像使用 inSampleSize 值为 4 的设置来解码,产生的 Bitmap 大小约为//512*384px。相较于完整图片占用 12M 的内存,这种方式只需 0.75M 内存 (假设 Bitmap 配置为//ARGB_8888)。
- opts.inSampleSize = 4;
- //6. 设置解码位图的尺寸信息
- opts.inInputShareable = true;
- Bitmap bitmap = BitmapFactory.decodeStream(input,null,opts);
- return bitmap;
- } catch (Exception e) {
- e.printStackTrace();
- return null;
- }
- }
以上方法通过使用 BitmapFactory.Options 以牺牲图片质量为代价,减少了内存的消耗。
测试代码下载(选择图库图片并设置到 ImageView 上)转载请注明:热爱改变生活.cn » Android BitmapFactory 的 OutOfMemoryError 解决方案
本博客只要没有注明“转”,那么均为原创。 转载请注明链接:sumile.cn » Android BitmapFactory 的 OutOfMemoryError 解决方案