美文网首页Android App架构
跟着源码学设计:Glide框架及源码解析(三)

跟着源码学设计:Glide框架及源码解析(三)

作者: 肖丹晨 | 来源:发表于2017-10-20 12:39 被阅读51次

    前言

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

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

    版权归作者所有,如有转发,请注明文章出处:http://www.jianshu.com/u/d43d948bef39

    相关文章:

    跟着源码学设计:Glide框架及源码解析(一)
    跟着源码学设计:Glide框架及源码解析(二)
    跟着源码学设计:Glide框架及源码解析(三)
    跟着源码学设计:Glide框架及源码解析(四)
    跟着源码学设计:Glide框架及源码解析(五)

    Glide内存缓存机制

    在之前的两篇中我们剖析了Glide的生命周期绑定机制和Glide的请求管理机制。接下来按说应该讲到request实际请求资源并回调刷新界面这一块了,但是为了更好的理解Glide在这一块的设计,我先大致的讲一讲Glide的内存缓存和管理机制。
    不同于其他常见网络加载框架只有LruCatch一种缓存机制,Glide内存为三块(非常牛逼巧妙的设计):

    • ActiveResourceCache:缓存当前正在使用的资源(注意是弱引用)
    • LruResourceCache: 缓存最近使用过但是当前未使用的资源,LRU算法
    • BitmapPool:缓存所有被释放的图片,内存复用,LRU算法

    注意:

    • LruResourceCache和ActiveResourceCache设计是为了尽可能的资源复用
    • BitmapPool的设计目的是为了尽可能的内存复用

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


    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前,内存占用情况

    使用inbitmap前,内存占用情况

    使用inbitmap后,内存占用情况

    使用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机制

    ActiveResourceCache的设计
    • 如图,当系统内存不足时,LruMemoryCache会根据LRU算法移除一些资源(bitmap)
    • 针对移除的资源,系统在GC时会回收资源(bitmap)以释放内存
    • 当应用再次需要次资源时,需要重新分配内存,重新对资源文件进行解析生成bitmap
      1)这样会造成内存抖动;
      2)比较耗费时间,影响流畅度(GC也比较频繁)

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

    ActiveResourceCache的设计
    • 如图,当系统内存不足时,LruResourceCache会根据LRU算法移除一些资源(resource)到BitmapPool
    • 到BitmapPool会根据LRU算法移除一些资源(bitmap)
    • 当应用再次需要资源时,会优先复用到BitmapPool中的bitmap对象(复用其内存),只需刷新bitmap的像素数据
      1)这样能有效地降低内存抖动;
      2)由于很多情况下可以复用废弃bitmap的内存,因此避免了内存分配等造成的性能损耗,系统比较流畅
      3)降低了系统GC的频率
      4)LruResourceCache和BitmapPool中都是当前不在使用的资源,做整体的资源回收那叫一个酸爽。

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

    相关文章

      网友评论

        本文标题:跟着源码学设计:Glide框架及源码解析(三)

        本文链接:https://www.haomeiwen.com/subject/ditvuxtx.html