【Android Developers Training】 56. 更效率地加载大图片
注:本文翻译自Google官方的Android Developers Training文档,译者技术一般,由于喜爱安卓而产生了翻译的念头,纯属个人兴趣爱好。
原文链接:http://developer.android.com/training/displaying-bitmaps/load-bitmap.html
图像的的形状和尺寸千变万化。在很多情况下它们比一般的应用UI所需要的尺寸更大一些。例如,在系统图库这个应用中,显示的照片是用你的Android设备拍摄的照片,它们比起屏幕的尺寸来说要大多了。
假设你现在只有有限的内存,那么在理想情况下你希望在内存中加载分辨率更小的图片。这个低分辨率版本的图片需要和将它显示出来的UI组件的尺寸相匹配。一个过高分辨率的图片并不会带来什么改善视觉体验,反而会消耗大量的内存空间,并且因为在运行时需要调整图片的尺度而导致应用性能表现欠佳。
这节课将带你学习通过加载一个大位图的减采样版本的图片到内存中,以此来防止应用的内存空间耗尽。
一). 读取位图的尺寸和类型
BitmapFactory类提供了一些解码方法(decodeByteArray(),decodeFile(),decodeResource()等)来为不同的源创建位图。应该基于你的图像数据源选择最合适的解码方法。这些方法尝试为构建好的图像分配空间,因此它很容易导致OutOfMemory异常。每种解码方法都有额外的参数选项可以让你通过BitmapFactory.Options类指定解码选项。在解码时,将inJustDecodeBounds属性设置为true可以防止内存溢出,如果不设置outWidth,outHeight和outMimeType的话,那么就会对该图像对象返回null。这个技术逼迫你在构造(和分配内存时)之前先读取图像的尺寸和图像数据的类型。
BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeResource(getResources(), R.id.myimage, options);
int imageHeight = options.outHeight;
int imageWidth = options.outWidth;
String imageType = options.outMimeType;
为了避免OutOfMemory异常,在解码图像之前检查它的尺寸,除非你完全相信提供给你图像的源会给你尺寸正好合适的图像数据,它能够符合有限的存储空间。
二). 加载一个缩小版本的图像到存储当中
现在这个图像的尺寸已经知道了,它们可以被用来这个完整的图片能否被加载到内存中,或者一个减采样的版本是否要被加载。下面是一些要考虑的因素:
- 估计一下如果加载完整图片的话内存的使用情况。
- 结合应用中其他内存的需求,决定这幅图片能使用多少大的内存空间。
- 这个图片要被加载到的ImageView或UI组建的尺寸。
- 当前设备的屏幕尺寸和分辨率。
例如,如果要把一幅1024x768的图片加载到一个大小为128x96大小的ImageView,显然这么做事不值得的。
为了告诉解码器对图像进行减采样,加载一个更小的版本到内存中,在你的BitmapFactory.Options对象中将inSampleSize设置为true。例如,一个分辨率为2048x1536的图像加上inSampleSize设置为4的选项后,会产生一幅大小为512x384的图。将它加载进系统需要使用0.75MB而不是全尺寸图像所需要的12MB(假定位图配置为ARGB_8888)。下面的方法用来计算一个图像的减采样版本(如果图像过大的话):
public static int calculateInSampleSize(
BitmapFactory.Options options, int reqWidth, int reqHeight) {
// Raw height and width of image
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; // Calculate the largest inSampleSize value that is a power of 2 and keeps both
// height and width larger than the requested height and width.
while ((halfHeight / inSampleSize) > reqHeight
&& (halfWidth / inSampleSize) > reqWidth) {
inSampleSize *= 2;
}
} return inSampleSize;
}
Note:
从上述代码可以看到,在计算减采样因数时,以2为级数增加, 选择以2为级数的原因是解码器在减采样时也是选择以2为级数时最接近的那个数字做减采样的,具体的阐述可以查看:inSampleSize的文档
为了用这个方法,首先在解码时,将inJustDecodeBounds设置为true,将选项传递进去然后再使用新的inSampleSize值解码,并把inJustDecodeBounds设置为false。
public static Bitmap decodeSampledBitmapFromResource(Resources res, int resId,
int reqWidth, int reqHeight) { // First decode with inJustDecodeBounds=true to check dimensions
final BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeResource(res, resId, options); // Calculate inSampleSize
options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight); // Decode bitmap with inSampleSize set
options.inJustDecodeBounds = false;
return BitmapFactory.decodeResource(res, resId, options);
}
这个方法使得将任意大尺寸的图片加载到值显示100x100大小的ImageView中时,非常方便,就像下面代码所显示的那样:
mImageView.setImageBitmap(
decodeSampledBitmapFromResource(getResources(), R.id.myimage, 100, 100));
你也可以通过替换适当的BitmapFactory.decode*方法(如果需要的话),对来自其他源的照片做类似的处理过程。
【Android Developers Training】 56. 更效率地加载大图片的更多相关文章
- Android开发中如何解决加载大图片时内存溢出的问题
Android开发中如何解决加载大图片时内存溢出的问题 在Android开发过程中,我们经常会遇到加载的图片过大导致内存溢出的问题,其实类似这样的问题已经屡见不鲜了,下面将一些好的解决方案分享给 ...
- Android(java)学习笔记236:多媒体之加载大图片到内存(Bitmap API)
1.Bitmap (API使用) android里面的bitmap中,一个像素点需要4个byte去表示,这是因为android表示颜色是" argb ":其中 a 表示是透明度,然 ...
- Android简易实战教程--第二十八话《加载大图片》
Android系统以ARGB表示每个像素,所以每个像素占用4个字节,很容易内存溢出.假设手机内存比较小,而要去加载一张像素很高的图片的时候,就会因为内存不足导致崩溃.这种异常是无法捕获的 内存不足并不 ...
- Android Camera开发系列(上)——Camera的基本调用与实现拍照功能以及获取拍照图片加载大图片
Android Camera开发系列(上)--Camera的基本调用与实现拍照功能以及获取拍照图片加载大图片 最近也是在搞个破相机,兼容性那叫一个不忍直视啊,于是自己翻阅了一些基本的资料,自己实现了一 ...
- Android -- 加载大图片到内存,从gallery获取图片,获取图片exif信息
1. 加载大图片到内存,从gallery获取图片 android默认的最大堆栈只有16M, 图片像素太高会导致内存不足的异常, 需要将图片等比例缩小到适合手机屏幕分辨率, 再加载. 从gallery ...
- 我的Android进阶之旅------>Android疯狂连连看游戏的实现之加载界面图片和实现游戏Activity(四)
正如在<我的Android进阶之旅------>Android疯狂连连看游戏的实现之状态数据模型(三)>一文中看到的,在AbstractBoard的代码中,当程序需要创建N个Piec ...
- Android(java)学习笔记179:多媒体之加载大图片到内存(Bitmap API)
1. Bitmap (API使用) android里面的bitmap中,一个像素点需要4个byte去表示,这是因为android表示颜色是" argb ":其中 a 表示是透明度, ...
- 图片_ _Android有效解决加载大图片时内存溢出的问题 2
Android有效解决加载大图片时内存溢出的问题 博客分类: Android Android游戏虚拟机算法JNI 尽量不要使用setImageBitmap或 setImageResource或 Bit ...
- android95 缩放加载大图片
MainActivity: package com.itheima.loadimage; import android.os.Bundle; import android.app.Activity; ...
随机推荐
- 转:Java compiler level does not match the version of the installed Java project facet
a.问题描述:eclipse加载新的项目后报一个错误,具体描述如下: Description Resource PathLocation Type Java compiler level does n ...
- Java学习笔记——序列化和反序列化
寒雨连江夜入吴,平明送客楚山孤. 洛阳亲友如相问,一片冰心在玉壶. --芙蓉楼送辛渐 持久化数据的第一种方式.在序列化之前也可以把数据打散逐行存储在文件中,然后在逐行读取. 比如定Student类 用 ...
- 区别client、offset、scroll系列以及event的几个距离属性
element元素结点属性 一. offset系列 1.offsetWidth 和offsetHeight element.offsetWidth是一个只读属性,它包括了: css width + p ...
- 精益IT组织与分享式领导
精益IT组织 未来的组织将专注于同行业的产品或业务流--其他的一切,包括专家和管理者在内,都是为了让一线工作人员可以第一时间就做好,而又不会遇到任何麻烦.最大的制约不是技术:真正的挑战是变 ...
- 基于python的爬虫(一)
抓取网页 python核心库 urllib2 实现对静态网页的抓取,不得不说,"人生苦短,我用python"这句话还是有道理的,要是用java来写,这估计得20行代码 (对不住了博 ...
- js实用方法记录-js动态加载css、js脚本文件
js实用方法记录-动态加载css/js 附送一个加载iframe,h5打开app代码 1. 动态加载js文件到head标签并执行回调 方法调用:dynamicLoadJs('http://www.yi ...
- Fast Fourier Transform ——快速傅里叶变换
问题: 已知$A=a_{0..n-1}$, $B=b_{0..n-1}$, 求$C=c_{0..2n-2}$,使: $$c_i = \sum_{j=0}^ia_jb_{i-j}$$ 定义$C$是$A$ ...
- Java基础知识二次学习--第七章 容器
第七章 容器 时间:2017年4月27日15:08:30 章节:07章01节~07章04节 视频长度:20:21 +12:38 +3:55 +2:57 内容:容器API 心得: Java API ...
- [oracle]Oracle数据库安全管理
目录 + 1.数据库安全控制策略概述 + 2.用户管理 + 3.资源限制与口令管理 + 4.权限管理 + 5.角色管理 + 6.审计 1.数据库安全控制策略概述 安全性是评估一个数据库的重 ...
- 6.类似Object监视器方法的Condition接口
在<1.有关线程.并发的基本概念>中,我们利用synchronized关键字.Queue队列.以及Object监视器方法实现了生产者消费者,介绍了有关线程的一些基本概念.Object类提供 ...