Android官方开发文档Training系列课程中文版:高效显示位图之加载大位图

原文地址:http://android.xsoftlab.net/training/displaying-bitmaps/index.html

引言

学习如何使用一种常规的手段来处理及加载Bitmap对象,这种方式除了使用户界面是可响应的之外,还会避免超出内存的限制。如果你不小心点的话,位图会迅速的将那些可怜的内存消耗殆尽,并会导致程序崩溃,因为这会产生一种可怕的异常:

java.lang.OutofMemoryError: bitmap size exceeds VM budget.

这里列举出了一些原因来说明为什么加载位图对于Android程序来说是非常棘手的:

  • 移动设备通常含有有限的资源。Android设备对于单个程序只有少量的16MB可用内存。虚拟机兼容性(Virtual Machine Compatibility)针对于各种的屏幕尺寸和密度给出了最低限度的程序内存要求。程序应该在极小的内存空间下充分利用内存空间。无论如何要记住一点,很多设备配备了更高的限制。
  • 位图通常会消耗掉不少内存,尤其是丰富的图片,就像照片这样的。举个例子,Galaxy Nexus上的相机拍的照片会达到2592x1936个像素(五百万像素)。如果位图配置使用的是ARGB_8888(这在Android 2.3以前是默认的),那么加载这张照片到内存中就需要花费掉19MB的内存(2592*1936*4个字节),这会立即耗尽某些设备上的所有内存。
  • Android的APP界面有时会很频繁的请求一些图片来加载。有些组件比如ListView, GridView及ViewPager,它们有个共同的特性就是需要同时在屏幕上加载多个位图并会在屏幕之外的地方加载以便在手指滑动的时候显示出来。

有效加载大图

图片会有各种形状和大小。在很多情况下它们会比用户界面上所要求的尺寸要大。举个例子,系统的相册应用所展示的用相机拍摄的照片的分辨率通常要比屏幕的密度要高。

鉴于在有限的内存中工作,理想上只用加载低分辨率的版本就可以。低分辨率的版本应该匹配到展示这张图片的控件大小。图片的更高分辨率不会在视觉上有更佳的效果,但是这仍然会消耗宝贵的内存空间,由于额外的动态扩展,这会招致额外的性能开销。

这节课会讨论将大位图进行二次采样并将采样后的小版本加载到内存中的过程。这个过程并不会超出应用的内存限制。

读取位图的尺寸及类型

类BitmapFactory提供了若干个解码方法(decodeByteArray(), decodeFile(), decodeResource(), etc.)根据不同的资源来创建位图Bitmap。选择更加适合的解码方法取决于图片的数据资源。这些方法会在构造位图时尝试向内存申请空间,所以会轻易的造成OutOfMemory异常。每个解码方法都有一个附属特征,这个特征可以使你通过BitmapFactory.Options类来指定解码选项。设置inJustDecodeBounds属性为true可以避免在解码时向内存申请空间,这会返回一个空的位图,但是outWidth、outHeight和outMimeType这些设置除外。这项技术可以使你在构造位图(申请内存)之前提前读取图像数据的尺寸及类型。

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;

为了避免java.lang.OutOfMemory异常,需要在解码图片之前检查图片的尺寸,除非你对这些图像数据的尺寸绝对的信任,并且该尺寸对可用内存非常适用。

加载等比缩小的版本到内存

那么现在图片的尺寸是知道了,这尺寸可以被用来决定:是否全尺寸的图像应该被加载到内存中还是应该有个二次采样的版本加载到内存中。这里有一些因素需要考虑:

  • 往内存中加载全尺寸的图像应该估算要使用的内存大小。
  • 要加载的图片所需要的内存数量需要给应用预留一定的内存空间,不要消耗完全。
  • ImageView或者UI组件的尺寸是图像将要加载的尺寸。
  • 当前设备的屏幕尺寸与密度。

举个例子,加载一个1024*768像素的图片到内存中是没有价值的,如果这个图片最终被显示为一个128x96像素的缩略图的话。

为了告诉解码器需要进行二次采样,以便加载一个小版本的图像到内存中,需要设置BitmapFactory.Options对象的inSampleSize属性为true。举个例子,一张图片的分辨率为2048x1536,需要通过inSampleSize解码为4分之一大小的位图,大概是512x384。加载这样的图像只需要花费0.75MB内存,而全尺寸的图像则需要花费12MB的内存(假设位图的配置为ARGB_8888)。这里有一个方法可以来计算一个样本容量值,这个值是2的幂次方值并基于原图像的高度值与宽度值进行计算。

public static int calculateInSampleSize(BitmapFactory.Options options, int reqWidth, int reqHeight) {// Raw height and width of imagefinal 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的幂次方最为接近,依据inSampleSize文档。

为了使用这个方法,第一步需要将inJustDecodeBounds设置为true,然后将options交给BitmapFactory使用,然后再次使用一个新的inSampleSize和inJustDecodeBounds设置为false来再次使用:

public static Bitmap decodeSampledBitmapFromResource(Resources res, int resId,int reqWidth, int reqHeight) {// First decode with inJustDecodeBounds=true to check dimensionsfinal BitmapFactory.Options options = new BitmapFactory.Options();options.inJustDecodeBounds = true;BitmapFactory.decodeResource(res, resId, options);// Calculate inSampleSizeoptions.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight);// Decode bitmap with inSampleSize setoptions.inJustDecodeBounds = false;return BitmapFactory.decodeResource(res, resId, options);
}

这个方法可以很轻易的加载任何大尺寸的位图给ImageView,这个ImageView展示了一个100*100像素的缩略图,就像下面的代码所展示的这样:

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

你可以遵循类似的过程来对其它资源进行解码,如果需要的话,可以替代使用合适的BitmapFactory.decode*方法。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/479141.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

美团DB数据同步到数据仓库的架构与实践

背景 在数据仓库建模中,未经任何加工处理的原始业务层数据,我们称之为ODS(Operational Data Store)数据。在互联网企业中,常见的ODS数据有业务日志数据(Log)和业务DB数据(DB)两类。对于业务DB数…

论文浅尝 | AAAI2020 - 基于生成对抗的知识图谱零样本关系学习

论文笔记整理:耿玉霞,浙江大学直博生。研究方向:知识图谱,零样本学习等。来源:AAAI2020论文链接:https://arxiv.org/pdf/2001.02332.pdf本文是发表在AAAI2020上的一篇基于生成对抗网络进行知识图谱零样本关…

LeetCode 1184. 公交站间的距离

1. 题目 环形公交路线上有 n 个站,按次序从 0 到 n - 1 进行编号。我们已知每一对相邻公交站之间的距离,distance[i] 表示编号为 i 的车站和编号为 (i 1) % n 的车站之间的距离。 环线上的公交车都可以按顺时针和逆时针的方向行驶。 返回乘客从出发点…

【python】详解类class的继承、__init__初始化、super方法

原文链接; https://blog.csdn.net/brucewong0516/article/details/79121179?utm_mediumdistribute.pc_relevant_t0.none-task-blog-BlogCommendFromBaidu-1.control&depth_1-utm_sourcedistribute.pc_relevant_t0.none-task-blog-BlogCommendFromBaidu-1.control 通过之前…

追剧计划第三弹!UC Berkeley出品,全栈深度学习!

关注卖萌屋比较早的小伙伴,大概还记得2020年初时我们组织的斯坦福大学CS224N自然语言处理公开课追剧计划,以及后来的斯坦福大学CS520知识图谱公开课追剧活动。尽管活动已经结束很长一段时间,但是仍然有小伙伴后台问“什么时候开始下一波追剧哇…

Android官方开发文档Training系列课程中文版:高效显示位图之在非UI线程中处理图片

原文地址:http://android.xsoftlab.net/training/displaying-bitmaps/process-bitmap.html 我们在上节课Load Large Bitmaps Efficiently中讨论了BitmapFactory.decode*方法,说到了不应该在UI线程中执行读取数据的过程,尤其是从磁盘或者网络…

美团外卖iOS App冷启动治理

一、背景 冷启动时长是App性能的重要指标,作为用户体验的第一道“门”,直接决定着用户对App的第一印象。美团外卖iOS客户端从2013年11月开始,历经几十个版本的迭代开发,产品形态不断完善,业务功能日趋复杂;…

LeetCode 538. 把二叉搜索树转换为累加树(逆中序 根右左)

文章目录1. 题目2. 逆中序(根右左,降序循环遍历)1. 题目 给定一个二叉搜索树(Binary Search Tree),把它转换成为累加树(Greater Tree),使得每个节点的值是原来的节点值加上所有大于…

应用实践 | 电商应用——一种基于强化学习的特定规则学习模型

本文转载自公众号:浙大KG。作者:汪寒,浙江大学硕士,主要研究方向为知识图谱和自然语言处理。应用场景在电商实际应用中,每个商品都会被挂载到若干个场景,以图结构中的节点形式存在。商品由结构化信息表示&a…

20W奖金+实习机会:阿里巴巴达摩院最新时间序列赛事来了!

Datawhale赛事 赛事:2021“AI Earth”人工智能挑战赛2021“AI Earth”人工智能创新挑战赛,由阿里巴巴达摩院联合南京信息工程大学、国家气候中心、国家海洋环境预报中心、安徽省气象局共同创办。大赛以“AI助力精准气象和海洋预测”为主题,聚…

关于python中带下划线的变量和函数 的意义,class类带一个下划线和带两个下划线的定义

总结:变量:1. 前带_的变量: 标明是一个私有变量, 只用于标明, 外部类还是可以访问到这个变量2. 前带两个_ ,后带两个_ 的变量: 标明是内置变量,3. 大写加下划线的变量: 标明是 不会发生改变的全局变量函数:1. 前带_的变量: 标明是一个私有函数, 只用于标明,2. 前带两个_…

Android官方开发文档Training系列课程中文版:高效显示位图之位图缓存

原文地址:http://android.xsoftlab.net/training/displaying-bitmaps/cache-bitmap.html 往UI界面中加载单张图片的过程是很简单的,然而如果需要在某个时刻同时加载大量的图片,那么这事情就有些复杂了。在很多情况下,比如使用了L…

论文浅尝 | ICLR2020 - 基于组合的多关系图卷积网络

论文笔记整理:吴锐,东南大学计算机学院硕士。来源:ICLR 2020链接:https://arxiv.org/pdf/1911.03082.pdf动机目前针对于GCN的研究大多数都关注在学习无向图的结点表示上,然而我们在研究中更常见的通常是多关系图&#…

Hades:移动端静态分析框架

只有通过别人的眼睛,才能真正地了解自己 ——《云图》 背景 作为全球最大的互联网 生活服务平台,美团点评近年来在业务上取得了飞速的发展。为支持业务的快速发展,移动研发团队规模也逐渐从零星的小作坊式运营,演变为千人级研发军…

GitHub超级火!任意爬取,超全开源爬虫工具箱

文 | 程序员GitHub最近国内一位开发者在 GitHub 上开源了个集众多数据源于一身的爬虫工具箱——InfoSpider,一不小心就火了!!!有多火呢?开源没几天就登上GitHub周榜第四,标星1.3K,累计分支 172 …

Android官方开发文档Training系列课程中文版:高效显示位图之管理位图内存

原文地址:http://developer.android.com/training/displaying-bitmaps/manage-memory.html 除了在上一节中描述的步骤之外,还有一些细节上的事情可以促进垃圾回收器的回收及位图的复用。其推荐的策略取决于Android的目标版本。示例APP BitmapFun展示了如…

Pytorch与tensorflow模型转换

使用pytorch_pretrained_bert将tensorflow模型转化为pytorch模型:https://blog.csdn.net/sunyueqinghit/article/details/103458365/ bert_config.json bert_model.ckpt.data-00000-of-00001 bert_model.ckpt.index bert_model.ckpt.meta vocab.txt 比如&#xff…

LeetCode 413. 等差数列划分(DP)

1. 题目 一个数列的等差数列子数组有多少个。 A [1, 2, 3, 4]返回: 3, A 中有三个子等差数组: [1, 2, 3], [2, 3, 4] 以及自身 [1, 2, 3, 4]。2. 解题 状态公式 if(A[i]−A[i−1]A[i−1]−A[i−2]),thendp[i]dp[i−1]1,i>2if (A[i]-A[i-1] A[i-1]-A[i-2]) , \quad then \…

技术动态 | 针对复杂问题的知识图谱问答最新进展

本文转载自公众号:PaperWeekly。作者:付彬、唐呈光、李杨、余海洋、孙健单位:阿里巴巴达摩院小蜜Conversational AI团队背景介绍知识图谱问答(KBQA)利用图谱丰富的语义关联信息,能够深入理解用户问题并给出…

百度提出新冠高风险小区预警算法,AAAI21收录!

编:夕小瑶几个月前,小屋推送了一期上帝视角看新型冠状病毒(COVID-19)对公众出行影响的顶会论文解读——《这篇顶会paper,讲述了疫情期间憋疯的你和我》,这篇有趣的paper来自百度地图团队,发表在…