Glide加载图片原理----转载

             以前项目上用的是Volley的ImageViewRequest进行图片加载的。可后来随着的项目的精细化,我觉得将图片请求和json的数据请求分离使用这样会更好。在网上查了很多资料,也进行了实践比较。我选择了okHhttp+Glide作为网络请求的方式在项目上。

       okHttp我会在以后文章介绍,今天只要看看Glide用法与原理分析。这些都是我在网上整理的,大家如果要看原创,这是网址Google推荐的图片加载库Glide介绍

       Glide是谷歌为我们介绍了一个图片加载库,作者是bumptech。这个库被广泛的运用在google的开源项目中,包括2014年google I/O大会上发布的官方app。 它的使用比较方便。需要V4包的支持。导入Glide架包即可。


Glide.with(context)
    .load("http://inthecheesefactory.com/uploads/source/glidepicasso/cover.jpg")
    .into(ImageView);
这里的Context可以是Activity,Fragment等。它默认的Bitmap的格式RGB_565,同时他还可以指定图片大小;默认使用HttpUrlConnection下载图片,可以配置为OkHttp或者Volley下载,也可以自定义下载方式。

        Glide支持图片磁盘缓存,默认是内部存储。Glide缓存的是跟ImageView尺寸相同的。

    Glide.with(this)  
         .load("http://nuuneoi.com/uploads/source/playstore/cover.jpg")  
         .diskCacheStrategy(DiskCacheStrategy.ALL)  
         .into(ivImgGlide);  
这样不仅可以缓存ImageView大小尺寸还可以缓存其他尺寸。下次再加载ImageView的图片时,全尺寸的图片将会从缓存中取出,重新调整大小,然后再次缓存。这样加载图片显示会很快。

        下来我想说Glide的原理。具体可以查看Glide图片加载器详解

     1.Glide的资源获取组件:

  • Model: 原始资源,比如Url,AndroidResourceId, File等
  • Data: 中间资源,比如Stream,ParcelFileDescriptor(ContentProvider共享文件时比较常用,其实就是操作系统的文件描述符的封装,里面有in out err三个取值。也有人说是链接建立好之后的socket句柄。)等
  • Resource:直接使用的资源,包括Bitmap,Drawable等

      2.Glide库的资源复用:

  • Android的内存申请几乎都在new的时候发生,而new较大对象(比如Bitmap时),更加容易触发GC_FOR_ALLOW。所以Glide尽量的复用资源来防止不必要的GC_FOR_ALLOC引起卡顿。
  • 最显著的内存复用就是内存LruResourceCache(第一次从网络或者磁盘上读取到Resource时,并不会保存到LruCache当中,当Resource被release时,也就是View不在需要此Resource时,才会进入LruCache当中)
  • 还有BitmapPool(Glide会尽量用图片池来获取到可以复用的图片,获取不到才会new,而当LruCache触发Evicted时会把从LruCache中淘汰下来的Bitmap回收,也会把transform时用到的中间Bitmap加以复用及回收)
     3.Glide库图片池:

  • 4.4以前是Bitmap复用必须长宽相等才可以复用
  • 4.4及以后是Size>=所需就可以复用,只不过需要调用reconfigure来调整尺寸
  • Glide用AttributeStategy和SizeStrategy来实现两种策略
  • 图片池在收到传来的Bitmap之后,通过长宽或者Size来从KeyPool中获取Key(对象复用到了极致,连Key都用到了Pool),然后再每个Key对应一个双向链表结构来存储。每个Key下可能有很多个待用Bitmap
  • 取出后要减少图片池中记录的当前Size等,并对Bitmap进行eraseColor(Color.TRANSPAENT)操作确保可用
    4.Glide加载发起流程:
  1. Glide.with(context)创建RequestManager
    • RequestManager负责管理当前context的所有Request
    • Context可以传Fragment、Activity或者其他Context,当传Fragment、Activity时,当前页面对应的Activity的生命周期可以被RequestManager监控到,从而可以控制Request的pause、resume、clear。这其中采用的监控方法就是在当前activity中添加一个没有view的fragment,这样在activity发生onStart onStop onDestroy的时候,会触发此fragment的onStart onStop onDestroy。
    • RequestManager用来跟踪众多当前页面的Request的是RequestTracker类,用弱引用来保存运行中的Request,用强引用来保存暂停需要恢复的Request。
  2. Glide.with(context).load(url)创建需要的Request
    • 通常是DrawableTypeRequest,后面可以添加transform、fitCenter、animate、placeholder、error、override、skipMemoryCache、signature等等
    • 如果需要进行Resource的转化比如转化为Byte数组等需要,可以加asBitmap来更改为BitmapTypeRequest
    • Request是Glide加载图片的执行单位
  3. Glide.with(context).load(url).into(imageview)
    • 在Request的into方法中会调用Request的begin方法开始执行
    • 在正式生成EngineJob放入Engine中执行之前,如果并没有事先调用override(width, height)来指定所需要宽高,Glide则会尝试去获取imageview的宽和高,如果当前imageview并没有初始化完毕取不到高宽,Glide会通过view的ViewTreeObserver来等View初始化完毕之后再获取宽高再进行下一步
     5.Glide加载资源:

  • GlideBuilder在初始化Glide时,会生成一个执行机Engine
  • Engine中包含LruCache缓存及一个当前正在使用的active资源Cache(弱引用)
  • activeCache辅助LruCache,当Resource从LruCache中取出使用时,会从LruCache中remove并进入acticeCache当中
  • Cache优先级LruCache>activeCache
  • Engine在初始化时要传入两个ExecutorService,即会有两个线程池,一个用来从DiskCache获取resource,另一个用来从Source中获取(通常是下载)
  • 线程的封装单位是EngineJob,有两个顺序状态,先是CacheState,在此状态先进入DiskCacheService中执行获取,如果没找到则进入SourceState,进到SourceService中执行下载
      6.Glide的Target:

         负责图片加载的回调

    总结

  • Glide库在使用过程中表现较好,滑动流畅,内存占用低
  • 代码扩展性极强,4.0版本更加如此,但来的问题就是过于复杂,不太便于阅读
  • 但仍会遇到有些需求Glide无法满足
    1. 设置加载图片的最大宽高
    2. PlaceHolder的图片形状不与加载的Bitmap相同会产生的抖动问题
    3. 无法指定删除某一个图片缓存的问题(可以用加signature的方式试其失效并重新下载,但不可以删除)
        在网上我还看到有Picasso的图片加载框架。其实和Glide用法很相似。


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值