专栏名称: 开发者全社区
分享和推送Java/Android方向的技术和文章,让你成为这方面的大牛,让你每天都成长一点。同时,我们也会邀请BAT的大牛分享原创!
目录
相关文章推荐
鸿洋  ·  Android Gradle Plugin插件详解 ·  昨天  
鸿洋  ·  简洁高效:类抖音视频列表设计思路 ·  2 天前  
stormzhang  ·  打工人何苦为难打工人 ·  3 天前  
鸿洋  ·  好用的HarmonyOS Next ... ·  4 天前  
51好读  ›  专栏  ›  开发者全社区

【强烈推荐】Android中高效的显示图片 - Bitmap的内存模型

开发者全社区  · 公众号  · android  · 2017-04-21 07:24

正文

相关阅读:

吊炸天!74款APP完整源码!

Android经久不衰最受欢迎的开源库整理,你一定用过10个以上,架构师必备

读Android源码之事件分发机制最全总结

相对于文字来说,图片的表达更直接、更有冲击力、更容易吸引用户的眼球。设计师们也理所当然的喜欢用图片来传达信息。但是对于开发者来说,图片就意味着大量的内存开销。要想APP在性能上有更好的表现,我们必须处理好显示图片所需要的每个环节。

Android中高效的显示图片 - 总结

前面几篇关于高效显示图片的文章已经实现了一个三级缓存、后台加载、裁剪大图的图片加载框架。框架大致如图所示,还有部分知识点图里没有体现(如Activity重建时利用Fragment保存数据),详细情况可以查看之前的文章。完整代码可以点击代码下载。

  1. 计算合适的加载尺寸,避免内存浪费 (加载大图)

  2. 使用后台线程将图片数据加载到内存中 (非UI线程加载)

  3. 通过缓存提高加载后的图片数据的使用率 (图片缓存)

  4. 确认图片不再使用后应尽快释放其所占用的内存空间。

管理bitmap内存

上面第4条之所以没有链接,是因为它就是本节要讲述的内容。加载图片时所申请的内存位于哪里,当图片不再使用时这部分已经申请的内存能否被其他需要加载的图片直接复用,当内存确实需要释放时又是如何回收的?这些疑问都会在本节内容中找到答案。

随着Android系统版本的不断的更新,Android团队在图片内存管理方面也做了一些优化。

  • 在Android 2.2 (API level 8)及其以下版本上,垃圾回收线程工作时,APP线程就得暂停,这一特性无疑会降低APP的性能。 Android 2.3开始实现了并发垃圾回收,这意味着一个bitmap对象不再任何被引用持有时,它所占有的内存空间会很快的被回收。

  • 在Android 2.3.3 (API level 10)及其以下版本上,bitmap的ARGB数据(backing pixel data)是存在native内存里的,而bitmap对象本身是存在Dalvik的堆里的。当bitmap对象不再被引用时,Dalvik的堆里的内存可以被垃圾回收期回收,但是native部分的内存却不会同步被回收。如果需要频繁的加载很多bitmap到内存中,即使Java层已经及时的释放掉不用bitmap,依旧有可能引起OOM。幸运的是从Android 3.0 (API level 11)开始,bitmap的ARGB数据和bitmap对象一起存在Dalvik的堆里了。这样bitmap对象和它的ARGB数据就可以同步回收了。


不同Android版本对bitmap内存管理方式不同,我们应对症下药的来优化不同版本上bitmap的内存使用。

Android 2.3.3 (API level 10)及其以下版本

在Android 2.3.3 (API level 10)及其以下版本上,Android开发文档推荐我们使用 recycle()方法。recycle()方法可以使APP尽可能快的回收bitmap所使用的native内存。

注意:recycle()方法是不可逆的,bitmap调用了recycle()之后就不能再使用了。使用recycle()之后的bitmap系统会抛出"Canvas: trying to use a recycled bitmap"的错误。所以调用recycle()方法之前一定要确认bitmap不会再使用了。

下面提供了一个使用recycle()的代码示例。我们使用了引用计数来判断bitmap是否是被显示或者被缓存。当一个bitmap不再被显示也没有被缓存时我们就调用bitmap的recycle()方法来释放内存。


Android 3.0 (API level 11)及其以上版本

Android 3.0 开始引入了BitmapFactory.Options.inBitmap字段。如果设置了这个字段,bitmap在加载数据时可以复用这个字段所指向的bitmap的内存空间。新增的这种内存复用的特性,可以优化掉因旧bitmap内存释放和新bitmap内存申请所带来的性能损耗。但是,内存能够复用也是有条件的。比如,在Android 4.4(API level 19)之前,只有新旧两个bitmap的尺寸一样才能复用内存空间。Android 4.4开始只要旧bitmap的尺寸大于等于新的bitmap就可以复用了。

下面是bitmap内存复用的代码示例。大致分两步:1、不用的bitmap用软引用保存起来,以备复用;2、使用前面保存的bitmap来创建新的bitmap。

  1. 保存废弃的bitmap

  2. 使用现有的废弃bitmap创建新的bitmap


上面代码片段中使用的addInBitmapOptions()会去废弃的bitmap中找一个能够被复用的bitmap设置到inBitmap字段。


canUseForInBitmap()方法用来判断bitmap是否能够被复用。

完整代码可以下载:点击“阅读原文”


(本文出处:http://www.jianshu.com/p/eadb0ef271b0)

看完本文有收获?请分享给更多人

Java和Android架构

欢迎关注我们,一起讨论技术,扫描和长按下方的二维码可快速关注我们。搜索微信公众号:JANiubility。

公众号:JANiubility