glide源码中包含了那种设计模式_跟着源码学设计:Glide框架及源码解析(三)...

前言

近期研究了一下Glide的图片加载框架,在这里和大家分享一下。由于代码研读有限,难免有错误的地方,了解的童鞋还望指正。学习小组QQ群: 193765960。

本篇是Glide框架及源码解析的第三篇,更多文章敬请关注后续文章。如果这篇文章对大家学习Glide有帮助,还望大家多多转载。

相关文章:

Glide内存缓存机制

在之前的两篇中我们剖析了Glide的生命周期绑定机制和Glide的请求管理机制。接下来按说应该讲到request实际请求资源并回调刷新界面这一块了,但是为了更好的理解Glide在这一块的设计,我先大致的讲一讲Glide的内存缓存和管理机制。

不同于其他常见网络加载框架只有LruCatch一种缓存机制,Glide内存为三块(非常牛逼巧妙的设计):

ActiveResourceCache:缓存当前正在使用的资源(注意是弱引用)

LruResourceCache: 缓存最近使用过但是当前未使用的资源,LRU算法

BitmapPool:缓存所有被释放的图片,内存复用,LRU算法

注意:

LruResourceCache和ActiveResourceCache设计是为了尽可能的资源复用

BitmapPool的设计目的是为了尽可能的内存复用

说的比较抽象,是不是懵逼了?别急,上图:

8cbe57a89c06

Glide内存缓存及管理机制

当我们需要显示某个资源时,Glide会先去查找LruResourceCache,找到了则将资源从LruResourceCache移除加入到ActiveResourceCache;

LruResourceCache找不到资源则查找ActiveResourceCache。

如果在ActiveResourceCache也找不到合适的资源,则会根据加载策略从硬盘或者网络加载资源。

获取数据后Glide会从BitmapPool中找寻合适的可供内存复用的废弃recycled bitmap(找不到则会重新创建bitmap对象),然后刷新bitmap的数据。

bitmap被转换封装为Resource缓存入ActiveResourceCache和Request对象中。

Request的target会获取resource中引用的bitmap并展示。

当target的资源需要release时,resource会根据缓存策略被缓存到LruResourceCache,同时ActiveResourceCache中的弱引用会被删除。如果,该资源不能缓存到LruResourceCache,则资源将被recycle到BitmapPool。

当需要回收内存时(比如系统内存不足或者生命周期结束),LruResourceCache将根据LRU算法recycle一些resource到BitmapPool。

BitmapPool会根据缓存池的尺寸和recycled resource的缓存策略来缓存resource的bitmap。

BitmapPool会根据LRU算法和缓存池的尺寸来释放一些老旧资源。

当系统GC时,则会回收可回收的资源释放内存

这样就完成了一个资源的完整的循环。

BitmapPool的内存复用机制

知识储备:

BitmapFactory.Options.inBitmap是AndroiD3.0新增的一个属性,如果设置了这个属性则会重用这个Bitmap的内存从而提升性能。

在SDK 11 -> 18之间,重用的bitmap大小必须是一致的,例如给inBitmap赋值的图片大小为100-100,那么新申请的bitmap必须也为100-100才能够被重用。从SDK 19开始,新申请的bitmap大小必须小于或者等于已经赋值过的bitmap大小。

新申请的bitmap与旧的bitmap必须有相同的解码格式,例如大家都是8888的,如果前面的bitmap是8888,那么就不能支持4444与565格式的bitmap了

使用inbitmap前,内存占用情况

8cbe57a89c06

使用inbitmap前,内存占用情况

使用inbitmap后,内存占用情况

8cbe57a89c06

使用inbitmap后,内存占用情况

下面看一下核心代码:Downsampler的downsampleWithSize()方法

private Bitmap downsampleWithSize(MarkEnforcingInputStream is, RecyclableBufferedInputStream bufferedStream,

BitmapFactory.Options options, BitmapPool pool, int inWidth, int inHeight, int sampleSize,

DecodeFormat decodeFormat) {

// Prior to KitKat, the inBitmap size must exactly match the size of the bitmap we're decoding.

Bitmap.Config config = getConfig(is, decodeFormat);

options.inSampleSize = sampleSize;

options.inPreferredConfig = config;

if ((options.inSampleSize == 1 || Build.VERSION_CODES.KITKAT <= Build.VERSION.SDK_INT) && shouldUsePool(is)) {

int targetWidth = (int) Math.ceil(inWidth / (double) sampleSize);

int targetHeight = (int) Math.ceil(inHeight / (double) sampleSize);

// BitmapFactory will clear out the Bitmap before writing to it, so getDirty is safe.

setInBitmap(options, pool.getDirty(targetWidth, targetHeight, config));

}

return decodeStream(is, bufferedStream, options);

}

@TargetApi(Build.VERSION_CODES.HONEYCOMB)

private static void setInBitmap(BitmapFactory.Options options, Bitmap recycled) {

if (Build.VERSION_CODES.HONEYCOMB <= Build.VERSION.SDK_INT) {

options.inBitmap = recycled;

}

}

让我们先看一下我们最常见到的LruMemoryCache机制

8cbe57a89c06

ActiveResourceCache的设计

如图,当系统内存不足时,LruMemoryCache会根据LRU算法移除一些资源(bitmap)

针对移除的资源,系统在GC时会回收资源(bitmap)以释放内存

当应用再次需要次资源时,需要重新分配内存,重新对资源文件进行解析生成bitmap

1)这样会造成内存抖动;

2)比较耗费时间,影响流畅度(GC也比较频繁)

让我们再来看一下Glide的机制

8cbe57a89c06

ActiveResourceCache的设计

如图,当系统内存不足时,LruResourceCache会根据LRU算法移除一些资源(resource)到BitmapPool

到BitmapPool会根据LRU算法移除一些资源(bitmap)

当应用再次需要资源时,会优先复用到BitmapPool中的bitmap对象(复用其内存),只需刷新bitmap的像素数据

1)这样能有效地降低内存抖动;

2)由于很多情况下可以复用废弃bitmap的内存,因此避免了内存分配等造成的性能损耗,系统比较流畅

3)降低了系统GC的频率

4)LruResourceCache和BitmapPool中都是当前不在使用的资源,做整体的资源回收那叫一个酸爽。

(本篇是Glide框架及源码解析的第三篇,更多文章敬请关注后续文章。版权归作者所有,如有转发,请注明文章出处:原文链接)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值