Glide(四):强大的图片缓存池和复用机制

Glide有一个很强大的Glide缓存策略和Glide复用机制,之前在里面栽过跟头,借此好好整理总结。


Glide缓存策略

Glide使用了类似三级缓存策略,分别是弱引用缓存、LruCache缓存、DiskLruCache缓存和网络加载。

默认情况下,Glide 会在开始一个新的图片请求之前检查以下多级的缓存:
活动资源 (Active Resources) - 现在是否有另一个 View 正在展示这张图片?
内存缓存 (Memory cache) - 该图片是否最近被加载过并仍存在于内存中?
资源类型(Resource) - 该图片是否之前曾被解码、转换并写入过磁盘缓存?
数据来源 (Data) - 构建这个图片的资源是否之前曾被写入过文件缓存?
前两步检查图片是否在内存中,如果是则直接返回图片。后两步则检查图片是否在磁盘上,以便快速但异步地返回图片。
如果四个步骤都未能找到图片,则Glide会返回到原始资源以取回数据(原始文件,Uri, Url等)。


Glide复用机制

除去了Glide的缓存机制以外,还有一个很强大的复用机制

1. 缓存和复用机制的区别和作用

简单来说,缓存是将数据存储起来,下次需要时就不用重新加载数据,直接拿来即用,作用是加快加载速度、避免相同的数据占用空间,降低内存占用;

复用的意思是重新使用,将已经不需要使用的数据空间重新拿来使用,他的作用是避免频繁申请内存,避免OOM,因为在短时间内快速申请释放内存,因为GC不及时,可能在短时间内来不及回收到足够的空间,导致OOM。所以复用的作用是减少内存抖动。

2. 原理是什么

(1)内存占用

在讲解glide如何复用bitmap之前,先来了解bitmap的内存占用问题。

在Android3.0之前,Bitmap的内存分配分为两部分,一部分是分配在Dalvik的VM堆中,而像素数据的内存是分配在Native堆中。

而到了Android3.0之后,Bitmap的内存则已经全部分配在VM堆上。意味着我们不需要手动释放bitmap内存,gc内存管理机制会帮忙管理。

(2)inMutable

inMutable是glide能够复用的基石,是bitmapFactory提供的一个参数,表示该bitmap是可变的,支持复用的。

Bitmap是android中最容易造成OOM的元凶之一,在Bitmap的解析参数,BitmapFactory.Options中提供了两个属性:inMutable、inBitmap

详情参考之前的文章《bitmap疑惑》

当你进行Bitmap的复用,需要设置inMutable为true,inBitmap设置想已经存在的Bitmap。

所谓复用的意思,就是将废弃不用准备recyle的bitmap,重新拿过来使用。

在使用inBitmap参数前,每创建一个Bitmap对象都会分配一块内存,而使用了inBitmap后, Bitmap的内存是被重新利用的。

(3)Bitmap复用使用条件

在Android 4.4之前,仅支持相同大小的bitmap,inSampleSize必须为1,而且必须采用jpeg或png格式。

在Android 4.4之后只有一个限制,就是被复用的bitmap尺寸要大于 新的bitmap,简单来说就是大图可以给小图复用。

(4)inMutable、inBitmap使用
BitmapFactory.Options largeOption = new BitmapFactory.Options();
largeOption.inMutable = true; // 设置inMutable
Bitmap largeBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.large, largeOption)

BitmapFactory.Options smallOption = new BitmapFactory.Options();
smallOption.inBitmap = largeBitmap; // 设置inBitmap被复用的Bitmap
Bitmap smallBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.small, smallOption);
(5)Lru算法

虽然说,将不再使用的bitmap保存起来能够避免频繁申请内存,减少内存抖动,但是同时也会耗用内存存储这些已经不再使用的bitmap,因此Glide使用LRU算法,类似LruCache,有一个最大空间限制。

3.源码分析

真正解析的是DownSampler类

DownSampler
// DownSampler
public Resource<Bitmap> decode(InputStream is, int requestedWidth, int requestedHeight,
      Options options, DecodeCallbacks callbacks) throws IOException {
   

    byte[] bytesForOptions = byteArrayPool.get(ArrayPool.STANDARD_BUFFER_SIZE_BYTES, byte[].class);
    BitmapFactory.Options bitmapFactoryOptions = getDefaultOptions();
    bitmapFactoryOptions.inTempStorage = bytesForOptions;

    DecodeFormat decodeFormat = options.get(DECODE_FORMAT);
    DownsampleStrategy downsampleStrategy = options.get(DOWNSAMPLE_STRATEGY);
    boolean fixBitmapToRequestedDimensions = options.get(FIX_BITMAP_SIZE_TO_REQUESTED_DIMENSIONS);
    boolean isHardwareConfigAllowed =
      options.get(ALLOW_HARDWARE_CONFIG) != null && options.get(ALLOW_HARDWARE_CONFIG);
    if (decodeFormat == DecodeFormat.PREFER_ARGB_8888_DISALLOW_HARDWARE) {
   
      isHardwareConfigAllowed = false;
    }

    try {
   
      Bitmap result = decodeFromWrappedStreams(is, bitmapFactoryOptions,
          downsampleStrategy, decodeFormat, isHardwareConfigAllowed, requestedWidth,
          requestedHeight, fixBitmapToRequestedDimensions, callbacks);
      return BitmapResource.obtain(result, bitmapPool);
    } finally {
   
      releaseOptions(bitmapFactoryOptions);
      byteArrayPool.put(bytesForOptions);
    }
  }

DownSampler 负责真正的解析加载图片,过载过程,

  1. inTempStorage

inTempStorage是一个bitmap解析的参数,带入一个buffer,创建临时文件,将图片存储的中间缓存空间

 BitmapFactory.Options bitmapFactoryOptions = getDefaultOptions();

 bitmapFactoryOptions.inTempStorage = bytesForOptions;
   
 byteArrayPool.put(bytesForOptions
  • 3
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值