2.3 基于信息流的图片加载框架
图片加载涉及负载、渲染、多线程、内存处理等技术,而基于信息流的图片加载更是将这一系列技术发挥到极致。下面将从图片加载、缓存机制以及对应的方案设计和实现来进行介绍。
2.3.1 图片加载
图片加载在信息流的产品中是一个随处可见的、最基本的功能,设计一套通用的基于信息流的图片加载框架可以大大节约开发时间。目前市面上流行的图片加载框架有 AndroidUniversal-Image-Loader、 Glide、 Picasso、 Fresco 等,这些框架都各有优缺点。在实际图片加载相关业务的开发工作中,若将以上图片加载框架全部引入,可能导致各种问题(如包大小、内存占用、异常崩溃等问题),因此需要对这些开源图片加载框架进行分析,并结合信息流产品业务进行框架的选择。需要优先考虑如下几个问题。
图片的加载速度。
占用的内存缓存大小。
是否支持 JPG、 PNG、 GIF 和 SVG 等图片格式。
库代码的大小。
列表图片是否可以高复用。
2.3.2 图片缓存机制
在图片加载过程中,缓存图片是最重要的事情,处理不好则会占用不必要的内存、出现大量内存泄漏、导致内存溢出。下面优先讨论一下缓存机制。
首先缓存设计分为 3 层: Bitmap 内存缓存、未解码图片内存缓存和磁盘缓存。
其中, Bitmap 内存缓存和未解码图片内存缓存的主要作用是,防止 App 将图片数据重复地读取到内存中;磁盘缓存的主要作用是,防止 App 从网络或其他地方重复地下载和读取数据。
1. Bitmap 内存缓存
Bitmap 内存缓存存储的是 Bitmap 对象,这些 Bitmap 对象可以立刻用于显示或者后续的转换操作。在 Android 5.0 以下版本的系统中, Bitmap 内存缓存位于 ashmem(匿名共享内存区域,此内存区域可无限扩大,不受 App 限制,通过 Options#inPurgeable 配置),这样 Bitmap对象的创建和释放将不会引发 GC,并且较少的 GC 会使你的 App 运行得更加流畅。在Android 5.0 及以上版本的系统中,内存管理有了很大的改进, Bitmap 内存缓存直接位于 Java的 heap(即 Java 堆上,内存有上限)上。因此,当 App 在后台运行时,该内存缓存会被清空。
2.未解码图片内存缓存
未解码图片内存缓存存储的是原始压缩格式的图片,也就是图片源。从该内存缓存中获取的图片在使用之前,需要先进行解码。如果有调整大小、旋转、剪裁等编码转换工作需要完成,那么这些工作会在解码之前进行。当 App 在后台运行时,这个内存缓存同样会被清空。(最少应该能缓存 2~3 个屏幕大小的 Bitmap。)
3.磁盘缓存
即将图片保存在本地磁盘中,保存的图片类型与未解码图片内存缓存相似,保存的都是未解码的原始压缩格式的图片,在使用之前需要经过解码等处理。
上面描述了缓存的 3 层设计,接下来介绍具体的内存占用优化方案、 Bitmap 回收机制及图片加载流程。
( 1)减少内存占用大小的方案
根据 ImageView 控件的尺寸获得对应大小的 Bitmap 来展示,如果按照 ImageView 的尺寸来裁剪并且缓存图片,则能让图片的内存占用大小减少到最小。
在图片解码成 Bitmap 的过程中采用 RGB_565 格式显示图片,相对于 ARGB_8888 格式来说,节