注:本文翻译自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可以防止内存溢出,如果不设置outWidthoutHeightoutMimeType的话,那么就会对该图像对象返回null。这个技术逼迫你在构造(和分配内存时)之前先读取图像的尺寸和图像数据的类型。

  1. BitmapFactory.Options options = new BitmapFactory.Options();
  2. options.inJustDecodeBounds = true;
  3. BitmapFactory.decodeResource(getResources(), R.id.myimage, options);
  4. int imageHeight = options.outHeight;
  5. int imageWidth = options.outWidth;
  6. String imageType = options.outMimeType;

为了避免OutOfMemory异常,在解码图像之前检查它的尺寸,除非你完全相信提供给你图像的源会给你尺寸正好合适的图像数据,它能够符合有限的存储空间。


二). 加载一个缩小版本的图像到存储当中

现在这个图像的尺寸已经知道了,它们可以被用来这个完整的图片能否被加载到内存中,或者一个减采样的版本是否要被加载。下面是一些要考虑的因素:

  • 估计一下如果加载完整图片的话内存的使用情况。
  • 结合应用中其他内存的需求,决定这幅图片能使用多少大的内存空间。
  • 这个图片要被加载到的ImageView或UI组建的尺寸。
  • 当前设备的屏幕尺寸和分辨率。

例如,如果要把一幅1024x768的图片加载到一个大小为128x96大小的ImageView,显然这么做事不值得的。

为了告诉解码器对图像进行减采样,加载一个更小的版本到内存中,在你的BitmapFactory.Options对象中将inSampleSize设置为true。例如,一个分辨率为2048x1536的图像加上inSampleSize设置为4的选项后,会产生一幅大小为512x384的图。将它加载进系统需要使用0.75MB而不是全尺寸图像所需要的12MB(假定位图配置为ARGB_8888)。下面的方法用来计算一个图像的减采样版本(如果图像过大的话):

  1. public static int calculateInSampleSize(
  2. BitmapFactory.Options options, int reqWidth, int reqHeight) {
  3. // Raw height and width of image
  4. final int height = options.outHeight;
  5. final int width = options.outWidth;
  6. int inSampleSize = 1;
  7.  
  8. if (height > reqHeight || width > reqWidth) {
  9.  
  10. final int halfHeight = height / 2;
  11. final int halfWidth = width / 2;
  12.  
  13. // Calculate the largest inSampleSize value that is a power of 2 and keeps both
  14. // height and width larger than the requested height and width.
  15. while ((halfHeight / inSampleSize) > reqHeight
  16. && (halfWidth / inSampleSize) > reqWidth) {
  17. inSampleSize *= 2;
  18. }
  19. }
  20.  
  21. return inSampleSize;
  22. }

Note:

从上述代码可以看到,在计算减采样因数时,以2为级数增加, 选择以2为级数的原因是解码器在减采样时也是选择以2为级数时最接近的那个数字做减采样的,具体的阐述可以查看:inSampleSize的文档

为了用这个方法,首先在解码时,将inJustDecodeBounds设置为true,将选项传递进去然后再使用新的inSampleSize值解码,并把inJustDecodeBounds设置为false

  1. public static Bitmap decodeSampledBitmapFromResource(Resources res, int resId,
  2. int reqWidth, int reqHeight) {
  3.  
  4. // First decode with inJustDecodeBounds=true to check dimensions
  5. final BitmapFactory.Options options = new BitmapFactory.Options();
  6. options.inJustDecodeBounds = true;
  7. BitmapFactory.decodeResource(res, resId, options);
  8.  
  9. // Calculate inSampleSize
  10. options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight);
  11.  
  12. // Decode bitmap with inSampleSize set
  13. options.inJustDecodeBounds = false;
  14. return BitmapFactory.decodeResource(res, resId, options);
  15. }

这个方法使得将任意大尺寸的图片加载到值显示100x100大小的ImageView中时,非常方便,就像下面代码所显示的那样:

  1. mImageView.setImageBitmap(
  2. decodeSampledBitmapFromResource(getResources(), R.id.myimage, 100, 100));

你也可以通过替换适当的BitmapFactory.decode*方法(如果需要的话),对来自其他源的照片做类似的处理过程。

【Android Developers Training】 56. 更效率地加载大图片的更多相关文章

  1. Android开发中如何解决加载大图片时内存溢出的问题

    Android开发中如何解决加载大图片时内存溢出的问题    在Android开发过程中,我们经常会遇到加载的图片过大导致内存溢出的问题,其实类似这样的问题已经屡见不鲜了,下面将一些好的解决方案分享给 ...

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

    1.Bitmap (API使用) android里面的bitmap中,一个像素点需要4个byte去表示,这是因为android表示颜色是" argb ":其中 a 表示是透明度,然 ...

  3. Android简易实战教程--第二十八话《加载大图片》

    Android系统以ARGB表示每个像素,所以每个像素占用4个字节,很容易内存溢出.假设手机内存比较小,而要去加载一张像素很高的图片的时候,就会因为内存不足导致崩溃.这种异常是无法捕获的 内存不足并不 ...

  4. Android Camera开发系列(上)——Camera的基本调用与实现拍照功能以及获取拍照图片加载大图片

    Android Camera开发系列(上)--Camera的基本调用与实现拍照功能以及获取拍照图片加载大图片 最近也是在搞个破相机,兼容性那叫一个不忍直视啊,于是自己翻阅了一些基本的资料,自己实现了一 ...

  5. Android -- 加载大图片到内存,从gallery获取图片,获取图片exif信息

    1. 加载大图片到内存,从gallery获取图片 android默认的最大堆栈只有16M, 图片像素太高会导致内存不足的异常, 需要将图片等比例缩小到适合手机屏幕分辨率, 再加载. 从gallery ...

  6. 我的Android进阶之旅------>Android疯狂连连看游戏的实现之加载界面图片和实现游戏Activity(四)

    正如在<我的Android进阶之旅------>Android疯狂连连看游戏的实现之状态数据模型(三)>一文中看到的,在AbstractBoard的代码中,当程序需要创建N个Piec ...

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

    1. Bitmap (API使用) android里面的bitmap中,一个像素点需要4个byte去表示,这是因为android表示颜色是" argb ":其中 a 表示是透明度, ...

  8. 图片_ _Android有效解决加载大图片时内存溢出的问题 2

    Android有效解决加载大图片时内存溢出的问题 博客分类: Android Android游戏虚拟机算法JNI 尽量不要使用setImageBitmap或 setImageResource或 Bit ...

  9. android95 缩放加载大图片

    MainActivity: package com.itheima.loadimage; import android.os.Bundle; import android.app.Activity; ...

随机推荐

  1. web乱码解决了

    web容易乱码,最近有乱码了,透死了! 搞了半天,终于好了: String comment = new String(request.getParameter("comment") ...

  2. Jenkins 远程构建任务

    开发过程中提交代码以后,如何不登录Jenkins就自动触发jenkins 任务来发布软件版本. 1.首先我们创建一个Jenkins任务. 2.选择"构建触发器"->勾选&qu ...

  3. nginx+tomcat+session共享(转)

    1 起因   最近对新开发的web系统进行了压力测试,发现tomcat默认配置下压到600人的并发登录首页响应速度就有比较严重的影响,一轮出现2000多个的 500和502错误.我把登录的时间统计做了 ...

  4. Unity应用架构设计(10)————绕不开的协程和多线程(Part 1)

    在进入本章主题之前,我们必须要了解客户端应用程序都是单线程模型,即只有一个主线程(Main Thread),或者叫做UI线程,即所有的UI控件的创建和操作都是在主线程上完成的.而服务器端应用程序,也就 ...

  5. 基于react的简单TODOList

    前段时间看了下react,写个栗子记录 页面效果如下 效果:展示代办事件,正文加了删除线的是已经完成的,未加横杠的是未完成的, 交互:1.在input里面输入新添加的内容,点击Add按钮添加代办事件 ...

  6. Libsvm使用资料

    原理: 1. pluskid(张弛原)的支持向量机教程(人家现在都是大牛了) http://blog.pluskid.org/?page_id=683 2. JerryLead机器学习教程 http: ...

  7. 入职这一段时间的总结,Don't Repeat Yourself.

    1.第一次接触到大型软件系统的开发,现在我们使用的是 python + flask +vue.js ,数据库:postgresql 2. 不要在自己不懂的情况下复制代码,每次分析一段代码的时候,就跟以 ...

  8. sql还原(.sql文件还原)

    第一步: 把还原文件直接拖到SQL Server 2012(或者其他版本)里面,这里以MyDB.sql为例

  9. LCA——求解最近公共祖先

    LCA 在有根树中,两个节点 u 和 v 的公共祖先中距离最近的那个被称为最近公共祖先(LCA,Lowest Common Ancestor). 有多种算法解决 LCA 或相关的问题. 基于二分搜索的 ...

  10. 音视频编解码问题:javaCV如何快速进行音频预处理和解复用编解码(基于javaCV-FFMPEG)

    前言: 前面我用了很多章实现了javaCV的基本操作,包括:音视频捕捉(摄像头视频捕捉和话筒音频捕捉),推流(本地音视频或者摄像头话筒混合推流到服务器),转流(rtsp->rtmp),收流(录制 ...