因为手机的内存资源是有限的,每个app可使用的内存是受限的。而现在采用高分辨率拍的照片往往很大。如果加载时不注意方法,很有可能会引起java.lang.OutofMemoryError: bitmap size exceeds VM budget. 异常而导致app奔溃退出。

另外ImageView支持的图片大小也是受限制的,比如整个App虽然只放一张图片,该图片大小也没超过整个app的内存上限。但该图片大小超过了ImageView的最大值,这也是有问题的。这时需要采取方法,在加载图片时缩小加载图片的大小。具体的策略看下面的介绍。

在真正创建和加载(需要实际耗费内存)一个图片对象时,我们可以先获取图像的大小信息。这里我们可以用到BitmapFactory.Options这个类。BitmapFactory.Options这个类,有一个字段叫做 inJustDecodeBounds 。SDK中对这个成员的说明是这样的:
“If set to true, the decoder will return null (no bitmap), but the out... fields will still be set, allowing the caller to query the bitmap without having to allocate the memory for its pixels.”

也就是说,如果我们把它设为true,那么BitmapFactory.decodeFile(String path, Options opt)并不会真的返回一个Bitmap给你,但它会把它的宽,高等基本信息取回来给你,这样就不会实际分配图片所需的内存。代码例子如下:

BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeResource(getResources(), R.drawable.pic1, options);
String text = "imageHeight:" + options.outHeight + ",imageWidth:"
+ options.outWidth + ",imageType:" + options.outMimeType;
Toast.makeText(this, text, Toast.LENGTH_LONG).show();

知道了图片的大小后,就可以考虑是将整个完整的图片加载到内存中,或是将缩小版加载到内存中。因为手机屏幕本身大小就那么大,没必要将原尺寸的图片加载进去。比如如果屏幕的大小为128x96,则将大小为1024x76的图片加载进去就没有意义。

为了告诉解码器将图片压缩后加载到内存中,需要设置BitmapFactory.Options对象的 inSampleSize 属性。比如,一张2048*1536的图片,如果设置inSampleSize的值为4. 缩小后图片的尺寸变为 512x384。占用的内存由原来的12M变为0.75M。下面的方法可以计算出一个图片应该设置的inSampleSize值:

public static int calculateInSampleSize(BitmapFactory.Options options,
int reqWidth, int reqHeight) {
// reqWidth、reqHeight是想要显示图片的大小,如屏幕的大小或ImageView控件的大小
final int height = options.outHeight;
final int width = options.outWidth;
int inSampleSize = 1; if (height > reqHeight || width > reqWidth) {
//说明图片的真实大小,大于需要显示的大小,则需要缩小图片
final int halfHeight = height / 2;
final int halfWidth = width / 2;
while ((halfHeight / inSampleSize) > reqHeight
&& (halfWidth / inSampleSize) > reqWidth) {
inSampleSize *= 2;
}
} return inSampleSize;
}

  有了适当的inSampleSize值后,就可以真正的执行加载图片的操作了。代码如下:

 final BitmapFactory.Options options = new BitmapFactory.Options();
options.inSampleSize = 2;
options.inJustDecodeBounds = false;
Bitmap bitmap = BitmapFactory.decodeResource(res, resId, options); ImageView imageView = (ImageView)findViewById(R.id.imageView1);
imageView.setImageBitmap(bitmap);

实际上对于大的图片,通过使用inSampleSize将图片变小后加载到内存中,只要不是变了非常小,不会影响视觉效果。但来的好处是显而意见的,会大大降低对内存的使用。一般对于大尺寸的照片(如用手机自身拍的),将inSampleSize设置为4一般不会影响视觉效果。

  

最新文章

  1. C++基础知识(4)---例外、异常处理
  2. include、merge 、ViewStub
  3. js 基本类型与引用类型的区别
  4. cmd for备忘
  5. SQLserver查看数据库端口 脚本
  6. Hadoop集群管理之内存管理
  7. python实现删除文件与目录的方法
  8. 关于“undefined reference to”错误
  9. 电脑升级完Xcode8后 注释快捷键无效的问题
  10. 第三篇:web之前端之JavaScript基础
  11. Qt 学习之路:QML 组件
  12. 用Processon在线绘制UML的尝试
  13. oracle 11g impdp时 报ORA-12899(转)
  14. PHP基础与JS操作的区别
  15. 数据挖掘进阶之序列模式挖掘GSP算法
  16. 死磕 java集合之CopyOnWriteArraySet源码分析——内含巧妙设计
  17. 第36节:Java当中的线程
  18. best practices for designing web api
  19. uboot——git代码仓
  20. 【IDEA】Intellij IDEA创建的Web项目配置Tomcat并启动Maven项目

热门文章

  1. 转 释一首美国民谣:沉默之音(The Sound Of Silence)
  2. Protel99se教程三:新建PCB文件以及PCB基本设定
  3. (C#)Windows Shell 外壳编程系列7 - ContextMenu 注册文件右键菜单
  4. MapReduce调度与执行原理之任务调度
  5. BeanFactory 和ApplicationContext
  6. File类常用方法
  7. _WSAStartup@8,该符号在函数 _main 中被引用
  8. Modular Inverse(模逆元,扩展欧几里德)
  9. SVN 让项目某些文件不受版本控制
  10. 【翻译自mos文章】oracle支持在RDBMS HOME 下的 符号链接( Symbolic Links)吗?