这是因为对于 Message 这类频繁使用的对象,如果每次使用的时候直接创建一个对象,那么可能会因频繁创建和销毁导致虚拟机 GC,从而造成页面卡顿现象,尤其是在低端设备上面。“池化”之后每次从池子中获取已经创建的对象进行复用,从而避免了虚拟机频繁 GC.
对于 Bitmap 这类对象和图片相关、占用内存较大的对象,如果频繁创建和销毁,对虚拟机的影响可能比 Message 要大得多,因此 Bitmap 复用显得非常重要。
2、从 Bitmap 的回收说起
先看下 Bitmap 是如何进行回收的吧。
根据官方的建议,在 Android 2.3 及以下的版本中建议使用 recycle()
回收内存,防止 OOM. 但是,使用这个方法的前提是需要确保这个位图不再被使用,否则回收之后再使用将会导致运行时错误。所以,官方的建议是通过引用计数的方式统计位图的引用,只有当位图不再被引用的时候再真正调用该方法进行回收。
官方文档参考:developer.android.com/topic/perfo…
在 Android 3.0 上面引入了 BitmapFactory.Options.inBitmap 字段。如果设置了此选项,那么采用 Options 对象的解码方法会在加载内容时尝试重复使用现有位图。这样可以复用现有的 Bitmap,减少对象创建,从而减少发生 GC 的概率。不过,inBitmap 的使用方式存在某些限制。特别是在 Android 4.4(API 级别 19)之前,系统仅支持大小相同的位图。在 Android 4.4 之后的版本,只要内存大小不小于需求的 Bitmap 都可以复用。
所以,当我们需要在 Android 中使用 Bitmap 的时候,应该考虑进行 Bitmap 复用以提升应用性能。但是,这些复杂的逻辑要如何封装呢?官方的建议是使用比较成熟的图片加载框架,比如 Glide. 所以,接下来我们来分析下 Glide 是如何实现 Bitmap 复用的。
3、Glide 的 BitmapPool
我们直接从 Glide 的 BitmapPool 开始分析。BitmapPool 是一个接口,定义如下:
public interface BitmapPool {
long getMaxSize();
void setSizeMultiplier(float sizeMultiplier);
// 往 pool 中插入 bitmap 以备复用
void put(Bitmap