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

原文地址:http://developer.android.com/training/displaying-bitmaps/manage-memory.html

除了在上一节中描述的步骤之外,还有一些细节上的事情可以促进垃圾回收器的回收及位图的复用。其推荐的策略取决于Android的目标版本。示例APP BitmapFun展示了如何使应用程序在不同的版本上高效的工作。

为了给这节课的知识奠定一些基础,下面有一些Android系统如何管理位图内存的一些改进需要了解:

  • 在Android 2.2之前,当垃圾回收器回收时,应用的线程会被停止。这会降低性能发生延迟。Android 2.3增加了并发收集垃圾的功能,这意味着内存回收不久之后位图不可再被引用。
  • 在Android 2.3.3之前,位图对应的支撑数据被存放在本地内存中。这与位图本身是分离的,它被存储在Dalvik堆栈之中。在意料之中位于本地内存中的像素数据是不会被释放的,可能会导致程序超过自身的内存限制然后崩溃。从在Android 3.0开始,像素数据与之相关的位图被一同存入了Dalvik虚拟机堆栈内。

下面的部分会介绍如何对不同的安卓版本进行位图内存的优化与管理。

在Android 2.3之前的版本上管理内存

在2.3之前推荐使用recycle()方法。如果你在APP内展示了大量的位图数据,那么你很有可能会遇到OutOfMemoryError错误。recycle()方法允许应用尽可能的回收内存。

Caution: 你应该在确保位图不再使用的时候使用recycle()方法。如果你调用了recycle()方法之后去尝试绘制这个位图,你将会得到错误:”Canvas: trying to use a recycled bitmap”。

下面的代码是recycle()方法的示例用法。它使用了引用计数的方式来追踪位图当前是处于被展示状态还是被缓存状态。当处于以下状况时,代码会回收位图:

  • 引用数mDisplayRefCount及 mCacheRefCount都是0。
  • 位图不为null,并且还没有被回收。
private int mCacheRefCount = 0;
private int mDisplayRefCount = 0;
...
// Notify the drawable that the displayed state has changed.
// Keep a count to determine when the drawable is no longer displayed.
public void setIsDisplayed(boolean isDisplayed) {synchronized (this) {if (isDisplayed) {mDisplayRefCount++;mHasBeenDisplayed = true;} else {mDisplayRefCount--;}}// Check to see if recycle() can be called.checkState();
}
// Notify the drawable that the cache state has changed.
// Keep a count to determine when the drawable is no longer being cached.
public void setIsCached(boolean isCached) {synchronized (this) {if (isCached) {mCacheRefCount++;} else {mCacheRefCount--;}}// Check to see if recycle() can be called.checkState();
}
private synchronized void checkState() {// If the drawable cache and display ref counts = 0, and this drawable// has been displayed, then recycle.if (mCacheRefCount <= 0 && mDisplayRefCount <= 0 && mHasBeenDisplayed&& hasValidBitmap()) {getBitmap().recycle();}
}
private synchronized boolean hasValidBitmap() {Bitmap bitmap = getBitmap();return bitmap != null && !bitmap.isRecycled();
}

在Android 3.0之后的版本上管理内存

Android 3.0中介绍了BitmapFactory.Options.inBitmap属性。如果设置了这个选项,那么解码方法会尝试去重用一个已经存在的位图。这也就是说位图的内存是可重用的,这可以促使改善性能,并且不需要再申请内存及释放内存。然而,inBitmap如何使用还有一些限制,在Android 4.4之前,仅支持相同大小的位图。更多信息,请看文档:inBitmap。

保存位图以便稍后使用

下面的代码演示了如何存储一个位图以便稍后使用。当APP运行在Android 3.0以上时,位图会被LruCache移除,接着一个引用位图的软性引用会被放置到一个HashSet中,以便稍后可能被用到:

Set<SoftReference<Bitmap>> mReusableBitmaps;
private LruCache<String, BitmapDrawable> mMemoryCache;
// If you're running on Honeycomb or newer, create a
// synchronized HashSet of references to reusable bitmaps.
if (Utils.hasHoneycomb()) {mReusableBitmaps =Collections.synchronizedSet(new HashSet<SoftReference<Bitmap>>());
}
mMemoryCache = new LruCache<String, BitmapDrawable>(mCacheParams.memCacheSize) {// Notify the removed entry that is no longer being cached.@Overrideprotected void entryRemoved(boolean evicted, String key,BitmapDrawable oldValue, BitmapDrawable newValue) {if (RecyclingBitmapDrawable.class.isInstance(oldValue)) {// The removed entry is a recycling drawable, so notify it// that it has been removed from the memory cache.((RecyclingBitmapDrawable) oldValue).setIsCached(false);} else {// The removed entry is a standard BitmapDrawable.if (Utils.hasHoneycomb()) {// We're running on Honeycomb or later, so add the bitmap// to a SoftReference set for possible use with inBitmap later.mReusableBitmaps.add(new SoftReference<Bitmap>(oldValue.getBitmap()));}}}
....
}

使用已经存在的位图

在运行中的APP内,解码方法会检查是否有已经存在的位图可以被再次使用:

public static Bitmap decodeSampledBitmapFromFile(String filename,int reqWidth, int reqHeight, ImageCache cache) {final BitmapFactory.Options options = new BitmapFactory.Options();...BitmapFactory.decodeFile(filename, options);...// If we're running on Honeycomb or newer, try to use inBitmap.if (Utils.hasHoneycomb()) {addInBitmapOptions(options, cache);}...return BitmapFactory.decodeFile(filename, options);
}

addInBitmapOptions():

private static void addInBitmapOptions(BitmapFactory.Options options,ImageCache cache) {// inBitmap only works with mutable bitmaps, so force the decoder to// return mutable bitmaps.options.inMutable = true;if (cache != null) {// Try to find a bitmap to use for inBitmap.Bitmap inBitmap = cache.getBitmapFromReusableSet(options);if (inBitmap != null) {// If a suitable bitmap has been found, set it as the value of// inBitmap.options.inBitmap = inBitmap;}}
}
// This method iterates through the reusable bitmaps, looking for one 
// to use for inBitmap:
protected Bitmap getBitmapFromReusableSet(BitmapFactory.Options options) {Bitmap bitmap = null;if (mReusableBitmaps != null && !mReusableBitmaps.isEmpty()) {synchronized (mReusableBitmaps) {final Iterator<SoftReference<Bitmap>> iterator= mReusableBitmaps.iterator();Bitmap item;while (iterator.hasNext()) {item = iterator.next().get();if (null != item && item.isMutable()) {// Check to see it the item can be used for inBitmap.if (canUseForInBitmap(item, options)) {bitmap = item;// Remove from reusable set so it can't be used again.iterator.remove();break;}} else {// Remove from the set if the reference has been cleared.iterator.remove();}}}}return bitmap;
}

最后,这里方法会检查候选位图是否满足大小:

static boolean canUseForInBitmap(Bitmap candidate, BitmapFactory.Options targetOptions) {if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {// From Android 4.4 (KitKat) onward we can re-use if the byte size of// the new bitmap is smaller than the reusable bitmap candidate// allocation byte count.int width = targetOptions.outWidth / targetOptions.inSampleSize;int height = targetOptions.outHeight / targetOptions.inSampleSize;int byteCount = width * height * getBytesPerPixel(candidate.getConfig());return byteCount <= candidate.getAllocationByteCount();}// On earlier versions, the dimensions must match exactly and the inSampleSize must be 1return candidate.getWidth() == targetOptions.outWidth&& candidate.getHeight() == targetOptions.outHeight&& targetOptions.inSampleSize == 1;
}
/*** A helper function to return the byte usage per pixel of a bitmap based on its configuration.*/
static int getBytesPerPixel(Config config) {if (config == Config.ARGB_8888) {return 4;} else if (config == Config.RGB_565) {return 2;} else if (config == Config.ARGB_4444) {return 2;} else if (config == Config.ALPHA_8) {return 1;}return 1;
}

下面片段所展示的方法会被上面的片段所调用。它会寻找存在的位图然后将其设置为值。注意这个方法只是对适合的匹配对象设置值。


PS:除了大家对图片的内存关心之外,可能大家还对图片的缓存,异步加载,加载大图也比较关注。

Note:这篇文章是前面有关位图的所有知识点的综合练习。

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

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

相关文章

Pytorch与tensorflow模型转换

使用pytorch_pretrained_bert将tensorflow模型转化为pytorch模型&#xff1a;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 \…

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

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

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

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

搜狗地图2016-Android-社招笔试题(包含Java基础部分)

下面是搜狗地图的社招笔试题&#xff0c;由于条件有限&#xff0c;全是手机拍的&#xff0c;请将就着看。另请忽略上面的答案&#xff0c;不一定准确。 大伙可在下方讨论答案&#xff0c;上方答案仅供参考&#xff0c;不一定准确。

机器学习常用的算法整理:线性回归、逻辑回归、贝叶斯分类、支持向量机、K-means聚类、决策树、随机森林以及常用的应用场景整理

什么是机器学习&#xff1f; 机器学习是计算机利用已有的数据(经验)得出了某种模型&#xff0c;并利用这些模型预测未来的一种方法。这个过程其实与人的学习过程极为相似&#xff0c;只不过机器是一个可以进行大维度数据分析而且可以不知疲倦地学习的“怪兽”而已。 具体的机器…

新一代数据库TiDB在美团的实践

1. 背景和现状 近几年&#xff0c;基于MySQL构建的传统关系型数据库服务&#xff0c;已经很难支撑美团业务的爆发式增长&#xff0c;这就促使我们去探索更合理的数据存储方案和实践新的运维方式。而随着分布式数据库大放异彩&#xff0c;美团DBA团队联合基础架构存储团队&#…

我在哥大读博的五年

文 | Mike Shou知乎&#xff08;ID&#xff1a;Showthem)本文已获作者授权&#xff0c;禁止二次转载0. 写在前面「 开始写这边总结的时候是三月&#xff0c;纽约成了疫情震中&#xff0c;看着新闻报道里的中央公园&#xff0c;中国城&#xff0c;第五大道&#xff0c;往事浮现&…

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

原文地址&#xff1a;http://android.xsoftlab.net/training/displaying-bitmaps/display-bitmap.html 这节课会将前面的知识点整合到一起&#xff0c;展示如何使用后台线程、位图缓存来加载多张图片到ViewPager或者GridView中&#xff0c;并会涉及并发处理及配置更改的相关知…

论文浅尝 | AAAI2020 - 多分量图卷积协同过滤方法

论文笔记整理&#xff1a;郝凯龙&#xff0c;南京大学硕士。来源&#xff1a;AAAI2020链接&#xff1a;https://arxiv.org/pdf/1911.10699.pdf动机推荐系统实际上是在做用户-商品二部图上的链路预测&#xff0c;仅仅用用户-商品之间的单一购买关系无法精确的进行描述为什么购买…

from torchcrf import CRF

报错CRF函数有问题&#xff0c;多了一个参数。通过源代码查找&#xff0c;发现两个torchcrf。通过pip list安装的时候是大写的TorchCRF&#xff0c;所以导入包的时候肯定也写大写的&#xff0c;没想到报错&#xff0c;后来改成全小写的就对了。

LeetCode 312. 戳气球(DP,难)

1. 题目 有 n 个气球&#xff0c;编号为0 到 n-1&#xff0c;每个气球上都标有一个数字&#xff0c;这些数字存在数组 nums 中。 现在要求你戳破所有的气球。每当你戳破一个气球 i 时&#xff0c;你可以获得 nums[left]∗nums[i]∗nums[right]nums[left] * nums[i] * nums[ri…

美团即时物流的分布式系统架构设计

本文根据美团资深技术专家宋斌在ArchSummit架构师峰会上的演讲整理而成。 背景 美团外卖已经发展了五年&#xff0c;即时物流探索也经历了3年多的时间&#xff0c;业务从零孵化到初具规模&#xff0c;在整个过程中积累了一些分布式高并发系统的建设经验。最主要的收获包括两点&…

Android官方开发文档Training系列课程中文版:OpenGL绘图之环境配置

原文地址&#xff1a;http://android.xsoftlab.net/training/graphics/opengl/index.html 引言 Android framework层为创建绚丽的功能性UI提供了大量的标准工具。然而&#xff0c;如果想要以更多方式来控制屏幕的绘制&#xff0c;或者在三维图形中绘制&#xff0c;那么就需要…

中文常用停用词表(哈工大停用词表、百度停用词表

中文常用停用词表&#xff08;哈工大停用词表、百度停用词表等&#xff1a;https://github.com/goto456/stopwords

论文浅尝 | AAAI2020 - 基于规则的知识图谱组合表征学习

论文笔记整理&#xff1a;康矫健&#xff0c;浙江大学计算机科学与技术系&#xff0c;硕士研究生。论文链接&#xff1a;https://arxiv.org/pdf/1911.08935.pdf发表会议&#xff1a;AAAI 2020Motivation现有的KG Embedding方法大部分仅关注每个三元组的结构化信息有部分的工作把…

26岁!年入100万,两周把 Github 项目推向全球榜首,他是怎么做的?

今天要为大家介绍一位很厉害的朋友 —— 小浩。九零后&#xff0c;20 年年收入近百万。 大家不需要质疑他的收入&#xff0c;在他没做公众号的时候&#xff0c;我知道收入已有五六十。而公众号&#xff0c;只是疫情期间他因无聊而产出的结果&#xff0c;那结果怎么样呢&#xf…

美团餐饮娱乐知识图谱——美团大脑揭秘

前言 “ I’m sorry. I can’t do that, Dave.” 这是经典科幻电影《2001: A Space Odyssey》里HAL 9000机器人说的一句话&#xff0c;浓缩了人类对终极人工智能的憧憬。让机器学会说这样简单一句话&#xff0c;需要机器具备情感认知、自我认识以及对世界的认识&#xff0c;来辅…

Android官方开发文档Training系列课程中文版:OpenGL绘图之图形定义

原文地址&#xff1a;http://android.xsoftlab.net/training/graphics/opengl/shapes.html 使用OpenGL绘制图形的第一步就是要定义一个图形。如果不清楚OpenGL如何绘制自定义图形的相关基础知识时&#xff0c;那么使用OpenGL一定要仔细。 这节课将会简单讲述OpenGl ES的坐标系…

LeetCode 765. 情侣牵手(贪心)

1. 题目 N 对情侣坐在连续排列的 2N 个座位上&#xff0c;想要牵到对方的手。 计算最少交换座位的次数&#xff0c;以便每对情侣可以并肩坐在一起。 一次交换可选择任意两人&#xff0c;让他们站起来交换座位。 人和座位用 0 到 2N-1 的整数表示&#xff0c;情侣们按顺序编号…