Android-高效加载大图

Android 高效加载大图

  • 前言
  • 读取位图尺寸和类型
  • 将按比例缩小的版本加载到内存中

前言

图片有各种形状和大小。在很多情况下,它们的大小超过了典型应用界面的要求。例如,系统“图库”应用会显示使用 Android 设备的相机拍摄的照片,这些照片的分辨率通常远高于设备的屏幕密度。

但是手机中每个应用的内存是有限的,程序占用了过高的内存就容易出现OOM(OutOfMemory)异常。理想情况下只希望在内存中加载较低分辨率的版本。分辨率较低的版本应与显示该版本的界面组件的大小相匹配。分辨率更高的图片不会带来任何明显的好处,但仍会占用宝贵的内存,并且会因为额外的动态缩放而产生额外的性能开销。

读取位图尺寸和类型

BitmapFactory类提供了几种用于从各种来源创建 Bitmap 的解码方法(decodeByteArray()decodeFile()decodeResource() 等)。根据图片数据源选择最合适的解码方法。这些方法尝试为构造的位图分配内存,因此很容易导致 OutOfMemory 异常。每种类型的解码方法都有额外的签名,允许你通过 BitmapFactory.Options 类指定解码选项。在解码时inJustDecodeBounds 属性设置为 true 可避免内存分配,为位图对象返回 null,但设置 outWidthoutHeightoutMimeType。此方法可让你在构造位图并为其分配内存之前读取图片数据的尺寸和类型。

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 异常,请先检查位图的尺寸,然后再对其进行解码,除非你绝对信任该来源可为你提供大小可预测的图片数据,以轻松适应可用的内存。

将按比例缩小的版本加载到内存中

既然图片尺寸已知,便可用于确定应将完整图片加载到内存中,还是应改为加载下采样版本。以下是需要考虑的一些因素:

  • 在内存中加载完整图片的估计内存使用量
  • 根据应用的其他内存要求,你愿意分配用于加载此图片的内存量
  • 用于展示这张图片的控件的实际大小
  • 当前设备的屏幕尺寸和分辨率

例如,如果 1024x768 像素的图片最终会在 ImageView 中显示为 128x96 像素缩略图,则不值得将其加载到内存中。

如需让解码器对图片进行下采样,以将较小版本加载到内存中,请在 BitmapFactory.Options 对象中将 inSampleSize 设置为 true。例如,分辨率为 2048x1536 且以 4 作为 inSampleSize 进行解码的图片会生成大约 512x384 的位图。将此图片加载到内存中需使用 0.75MB,而不是完整图片所需的 12MB(假设位图配置为 ARGB_8888)。下面的方法用于计算样本大小值,即基于目标宽度和高度的 2 的幂:

public static int calculateInSampleSize(BitmapFactory.Options options, int reqWidth, int reqHeight) {// 源图片的高度和宽度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;// 计算最大的 inSampleSize 值,该值应是 2 的幂次,// 且高度和宽度均大于所要求的高度和宽度。while ((halfHeight / inSampleSize) >= reqHeight&& (halfWidth / inSampleSize) >= reqWidth) {inSampleSize *= 2;}}return inSampleSize;
}

inSampleSize: 如果设置为 > 1 的值,则请求解码器对原始图像进行二次采样,返回较小的图像以节省内存。样本大小是任一维度中与解码位图中的单个像素相对应的像素数。例如,inSampleSize == 4 返回图像的宽度/高度为原始图像的 1/4,像素数为 1/16。任何<= 1的值都被视为与1相同。
注意: 解码器使用基于2的幂的最终值,任何其他值将向下舍入到最接近的2的幂。

如需使用此方法,先将 inJustDecodeBounds 设为 true 进行解码,传递选项,然后使用新的 inSampleSize 值并将 inJustDecodeBounds 设为 false 再次进行解码:

public static Bitmap decodeSampledBitmapFromResource(Resources res, int resId,int reqWidth, int reqHeight) {// 第一次解析将inJustDecodeBounds设置为true,来获取图片大小final BitmapFactory.Options options = new BitmapFactory.Options();options.inJustDecodeBounds = true;BitmapFactory.decodeResource(res, resId, options);// 计算inSampleSizeoptions.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight);// 使用计算的inSampleSize值再次解析图片options.inJustDecodeBounds = false;return BitmapFactory.decodeResource(res, resId, options);
}

采用此方法,可以轻松地将任意大尺寸的位图加载到显示 100x100 像素缩略图的 ImageView 中,如以下示例代码所示:

imageView.setImageBitmap(decodeSampledBitmapFromResource(getResources(), R.id.myimage, 100, 100));
BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.mipmap.screen_capture, options);
int imageHeight = options.outHeight;
int imageWidth = options.outWidth;
String imageType = options.outMimeType;
Log.i(TAG, "onCreate: bitmap == null ? " + (null == bitmap));
Log.i(TAG, "onCreate: width: " + imageWidth);
Log.i(TAG, "onCreate: height: " + imageHeight);
Log.i(TAG, "onCreate: type: " + imageType);// Decode bitmap with inSampleSize set
options.inJustDecodeBounds = false;
bitmap = BitmapFactory.decodeResource(getResources(), R.mipmap.screen_capture, options);
Log.i(TAG, "onCreate: size: " + (bitmap.getByteCount() / 1024 / 1024) + " MB");// Calculate inSampleSize
options.inSampleSize = calculateInSampleSize(options, 100, 100);
Log.i(TAG, "onCreate: inSampleSize: " + options.inSampleSize);bitmap = BitmapFactory.decodeResource(getResources(), R.mipmap.screen_capture, options);
imageHeight = options.outHeight;
imageWidth = options.outWidth;
imageType = options.outMimeType;
Log.i(TAG, "onCreate: bitmap == null ? " + (null == bitmap));
Log.i(TAG, "onCreate: width: " + imageWidth);
Log.i(TAG, "onCreate: height: " + imageHeight);
Log.i(TAG, "onCreate: type: " + imageType);
Log.i(TAG, "onCreate: size: " + (bitmap.getByteCount() / 1024) + " KB");

在这里插入图片描述

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

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

相关文章

如何实现公网访问本地内网搭建的WBO白板远程协作办公【内网穿透】

最近&#xff0c;我发现了一个超级强大的人工智能学习网站。它以通俗易懂的方式呈现复杂的概念&#xff0c;而且内容风趣幽默。我觉得它对大家可能会有所帮助&#xff0c;所以我在此分享。点击这里跳转到网站。 文章目录 前言1. 部署WBO白板2. 本地访问WBO白板3. Linux 安装cp…

《代码随想录》--二叉树(一)

《代码随想录》--二叉树 第一部分 1、二叉树的递归遍历2、二叉树的迭代遍历3、统一风格的迭代遍历代码4、二叉树的层序遍历226.翻转二叉树 1、二叉树的递归遍历 前序遍历 中序遍历 后序遍历 代码 前序遍历 class Solution {public List<Integer> preorderTraversal(T…

redis:五、缓存持久化(RDB和AOF)的开启和配置、面试回答模板

持久化 方案 redis中自身存在两种方案&#xff0c;分别叫RDB和AOF&#xff0c;来保障数据的持久化。其中前者默认开启&#xff0c;后者默认关闭。 redis是基于内存的&#xff0c;redis持久化的意思就是将redis数据&#xff0c;即内存数据写入磁盘等持久化存储设备当中。 RDB…

数字化医疗新篇章:构建智能医保支付购药系统

在迎接数字化医疗时代的挑战和机遇中&#xff0c;智能医保支付购药系统的建设显得尤为重要。本文将深入介绍如何通过先进的技术实现&#xff0c;构建一套智能、高效的医保支付购药系统&#xff0c;为全面建设健康中国贡献力量。 1. 引言 随着医疗科技的飞速发展&#xff0c;…

【网络安全技术】传输层安全——SSL/TLS

一、TLS位置及架构 TLS建立在传输层TCP/UDP之上&#xff0c;应用层之下。 所以这可以解决一个问题&#xff0c;那就是为什么抓不到HTTP和SMTP包&#xff0c;因为这两个在TLS之上&#xff0c;消息封上应用层的头&#xff0c;下到TLS层&#xff0c;TLS层对上层消息整个做了加密&…

vue3 插槽slot

插槽是子组件中的提供给父组件使用的一个占位符&#xff0c;用 <slot> 表示&#xff0c;父组件可以在这个占位符中填充任何模板代码&#xff0c;如 HTML、组件等&#xff0c;填充的内容会替换子组件的<slot> 元素。<slot> 元素是一个插槽出口 (slot outlet)&…

【Linux】磁盘分区管理及挂载/永久挂载管理

&#x1f468;‍&#x1f393;博主简介 &#x1f3c5;云计算领域优质创作者   &#x1f3c5;华为云开发者社区专家博主   &#x1f3c5;阿里云开发者社区专家博主 &#x1f48a;交流社区&#xff1a;运维交流社区 欢迎大家的加入&#xff01; &#x1f40b; 希望大家多多支…

Aegisub字幕入门篇

目录 中文文档 介绍 语法 fs 控制字体大小 fn 控制字体样式 ​编辑 滚动特效代码 淡入淡出代码 渐变代码 字体大小渐变 字体间距渐变 字体边缘模糊渐变 字体对齐方式渐变 字体的渐变色设置 竖向跑马灯制作&#xff0c;电影字幕片尾 文字抖动 批量设置特效样式 中…

系列五、DQL

一、DQL 1.1、概述 DQL的英文全称为&#xff1a;Data Query Language&#xff0c;中文意思为&#xff1a;数据查询语言&#xff0c;用大白话讲就是查询数据。对于大多数系统来说&#xff0c;查询操作的频次是要远高于增删改的&#xff0c;当我们去访问企业官网、电商网站&…

如何利用视频号爆款数据分析平台,实现播放变现?

利用视频号爆款数据分析平台了解当下视频号热点视频&#xff0c;以及那个分类更有潜力&#xff0c;可以即使进行预判&#xff0c; 变现是近年来非常流行的一种商业模式。视频号爆款数据分析平台是视频下载plus的一个功能&#xff0c;可以让用户通过每天都热点数据以及热门榜单…

【面试】Java最新面试题资深开发-微服务篇(1)

问题九&#xff1a;微服务 什么是微服务架构&#xff1f;它与单体架构相比有哪些优势和劣势&#xff1f;解释一下服务发现和服务注册是什么&#xff0c;它们在微服务中的作用是什么&#xff1f;什么是API网关&#xff08;API Gateway&#xff09;&#xff1f;在微服务中它有何…

LeetCode 每日一题 Day 13 || BFS

2415. 反转二叉树的奇数层 给你一棵 完美 二叉树的根节点 root &#xff0c;请你反转这棵树中每个 奇数 层的节点值。 例如&#xff0c;假设第 3 层的节点值是 [2,1,3,4,7,11,29,18] &#xff0c;那么反转后它应该变成 [18,29,11,7,4,3,1,2] 。 反转后&#xff0c;返回树的根…