读源码系列之路边跌倒的老太太我都不服,图片加载我只服Glide

热文导读 | 点击标题阅读

重磅,Google终于出手,向iOS靠拢?Android 9.0将禁止开发者使用非官方API

吊炸天!74款APP完整源码!

盘点流氓App驻留后台的奇技淫巧

博客:http://www.apkbus.com/blog-302849-63052.html


前言


        泰国举行的谷歌开发者论坛上,谷歌为我们介绍了一个名叫 Glide 的图片加载库,作者是bumptech。这个库被广泛的运用在google的开源项目中,包括2014年google I/O大会上发布的官方app。

        相信现在的App上面或多或少都会涉及到图片加载,从最初自己编写http请求下载,到各种第三方的库的使用。可谓是八仙过海各显神通,看到有很多博友对现有的库进行了对比,其中Picasso与Glide对比参照了一下,根据现有项目需求便选择了Glide。

Glide的特点

  1. 区别于其它的第三方加载库,它可以与activity、fragment的生命周期绑定,在Paused暂停加载,在Resumed的时候又自动重新加载。

  2. 支持Memory和Disk图片缓存

  3. 支持gif和webp格式图片

  4. 使用Bitmap Pool可以使Bitmap复用

  5. 对于回收的Bitmap会制动调用recycle,减少系统回收压力


总体设计


基本概念

  • RequestManager:请求管理,每一个Activity都会创建一个RequestManager,根据对应Activity的生命周期管理该Activity上所有的图片请求

  • Engine:加载图片的引擎,根据Request创建EngineJob和DecodeJob

  • EngineJob:图片加载

  • DecodeJob:图片处理


核心类介绍

3.1 Clide

        用于保存整个框架中的配置。
重要方法:

 public static RequestManager with(Context context) {
        RequestManagerRetriever retriever = RequestManagerRetriever.get();        return retriever.get(context);
 }

        用于创建RequsetManager,这里是Glide通过Activity/Fragment生命周期管理Request的原理所在,整个类很关键,主要原理是创建一个自定义的Fragment,然后通过自定义Fragment生命周期操作RequestManager,从而达到管理request。


        这里会将RequestManagerFragment生命周期事件回调通过RequestManager的构造函数传值。所以RequestManage就能响应RequestManagerFragment的生命周期

3.2 RequestManagerRetriever

 RequestManager supportFragmentGet(Context context, FragmentManager fm) {
        SupportRequestManagerFragment current = getSupportRequestManagerFragment(fm);
        RequestManager requestManager = current.getRequestManager();
        if (requestManager == null) {
            requestManager = new RequestManager(context, current.getLifecycle(), current.getRequestManagerTreeNode());
            current.setRequestManager(requestManager);
        }
        return requestManager;
    }

        这里判断是否只当前RequestManagerFragment是否存在RequestManager,保证一个Activity对应一个RequestManager, 这样有利于管理一个Activity上所有的Request。创建RequestManager的时候会将RequestManagerFragment中的回调接口赋值给RequestManager,达到RequestManager监听RequestManagerFragment的生命周期。

3.3 RequestManager

成员变量:

  1. Lifecycle lifecycle,用于监听RequestManagerFragment生命周期。

  2. RequestTracker requestTracker, 用于保存当前RequestManager所有的请求和带处理的请求。
    重要方法:

/**
     * Lifecycle callback that registers for connectivity events (if the android.permission.ACCESS_NETWORK_STATE
     * permission is present) and restarts failed or paused requests.
     */
    @Override
    public void onStart() {        // onStart might not be called because this object may be created after the fragment/activity's onStart method.
        resumeRequests();
    }    /**
     * Lifecycle callback that unregisters for connectivity events (if the android.permission.ACCESS_NETWORK_STATE
     * permission is present) and pauses in progress loads.
     */
    @Override
    public void onStop() {
        pauseRequests();
    }    /**
     * Lifecycle callback that cancels all in progress requests and clears and recycles resources for all completed
     * requests.
     */
    @Override
    public void onDestroy() {
        requestTracker.clearRequests();
    }
    ....        /**
     * Returns a request builder that uses the {@link com.bumptech.glide.load.model.ModelLoaderFactory}s currently
     * registered for the given model class for {@link InputStream}s and {@link ParcelFileDescriptor}s to load a
     * thumbnail from either the image or the video represented by the given model.
     *
     * <p>
     *     Note - for maximum efficiency, consider using {@link #from(Class)}} to avoid repeatedly allocating builder
     *     objects.
     * </p>
     *
     * @see #from(Class)
     *
     * @param model The model the load.
     * @param <T> The type of the model to load.
     */
    public <T> DrawableTypeRequest<T> load(T model) {        return (DrawableTypeRequest<T>) loadGeneric(getSafeClass(model)).load(model);
    }
    .........    public <Y extends Target<TranscodeType>> Y into(Y target) {
      ...
      Request previous = target.getRequest();      //停止当前target中的Request。
     if (previous != null) {
         previous.clear(); //这个地方很关键,见Request解析
          requestTracker.removeRequest(previous);
          previous.recycle();
       }
      ...       return target;
   }

3.4 DrawableRequestBuilder

        用于创建Request。 这里面包括很多方法,主要是配置加载图片的url、大小、动画、ImageView对象、自定义图片处理接口等。

3.5 Request

        主要是操作请求,方法都很简单。

   @Override
 public void clear() {
      ...      if (resource != null) {           //这里会释放资源
         releaseResource(resource);
      }
      ...
 }

        这里的基本原理是当有Target使用Resource(Resource见下文)时,Resource中的引用记数值会加一,当释放资源Resource中的引用记数值减一。当没有Target使用的时候就会释放资源,放进Lrucache中。

3.7 EngineResource

        实现Resource接口,使用装饰模式,里面包含实际的Resource对象

  1. void release() {  2.     if (--acquired == 0) {  3.         listener.onResourceReleased(key, this);  4.     }  5. }  
  6.  
  7. void acquire() {  8.     ++acquired;  9. }  
  10.  
  11. @Override  12. public void recycle() {  13.     isRecycled = true;  14.     resource.recycle();  15. }

        acquire和release两个方法是对资源引用计数;recycle释放资源,一般在Lrucache饱和时会触发。

3.8 Engine(重要)

        请求引擎,主要做请求的开始的初始化。

3.8.1 load方法

        这个方法很长,将分为几步分析

  1. 获取MemoryCache中缓存 首先创建当前Request的缓存key,通过key值从MemoryCache中获取缓存,判断缓存是否存在。

    1. private EngineResource<?> loadFromCache(Key key, boolean isMemoryCacheable) {2.     ....3.     EngineResource<?> cached = getEngineResourceFromCache(key);4.     if (cached != null) {5.         cached.acquire();6.         activeResources.put(key, new ResourceWeakReference(key, cached, getReferenceQueue()));7.     }8.     return cached;9. }10.  11. @SuppressWarnings("unchecked")12. private EngineResource<?> getEngineResourceFromCache(Key key) {13.     Resource<?> cached = cache.remove(key);14.  15.     final EngineResource result;16.     ...17.     return result;18. }

    (重点)从缓存中获取的时候使用的cache.remove(key),然后将值保存在activeResources中,然后将Resource的引用计数加一。
    优点:

    正使用的Resource将会在activeResources中,不会出现在cache中,当MemoryCache中缓存饱和的时候或者系统内存不足的时候,清理Bitmap可以直接调用recycle,不用考虑Bitmap正在使用导致异常,加快系统的回收。


  1. 获取activeResources中缓存
    activeResources通过弱引用保存recouse ,也是通过key获取缓存,

  1. private EngineResource<?> loadFromActiveResources(Key key, boolean isMemoryCacheable)

  1. 判断当前的请求任务是否已经存在

  1. EngineJob current = jobs.get(key);  2. if (current != null) {  3.     current.addCallback(cb);  4.     return new LoadStatus(cb, current);  5. }

        如果任务请求已经存在,直接将回调事件传递给已经存在的EngineJob,用于请求成功后触发回调。


  1. 执行请求任务

  1. EngineJob engineJob = engineJobFactory.build(key, isMemoryCacheable);  2. DecodeJob<T, Z, R> decodeJob = new DecodeJob<T, Z, R>(key, width, height, fetcher, loadProvider, transformation,  3.         transcoder, diskCacheProvider, diskCacheStrategy, priority);  4. EngineRunnable runnable = new EngineRunnable(engineJob, decodeJob, priority);  5. jobs.put(key, engineJob);  6. engineJob.addCallback(cb);  7. engineJob.start(runnable);

3.9 EngineRunnable

        请求执行Runnable,主要功能请求资源、处理资源、缓存资源。

  1. private Resource<?> decodeFromCache() throws Exception {  2.     Resource<?> result = null;  3.     try {  4.         result = decodeJob.decodeResultFromCache();  5.     } catch (Exception e) {  6.         if (Log.isLoggable(TAG, Log.DEBUG)) {  7.             Log.d(TAG, "Exception decoding result from cache: " + e);  8.         }  9.     }  10.  
  11.     if (result == null) {  12.         result = decodeJob.decodeSourceFromCache();  13.     }  14.     return result;  15. }  
  16.  
  17. private Resource<?> decodeFromSource() throws Exception {  18.     return decodeJob.decodeFromSource();  19. }

        加载DiskCache和网络资源。加载DiskCache包括两个,因为Glide默认是保存处理后的资源(压缩和裁剪后),缓存方式可以自定义配置。如果客户端规范设计,ImageView大小大部分相同可以节省图片加载时间和Disk资源。

3.10 DecodeJob

 public Resource<Z> decodeResultFromCache() throws Exception   public Resource<Z> decodeSourceFromCache() throws Exception
从缓存中获取处理后的资源。上面有关Key的内容,Key是一个对象,可以获取key和orginKey。decodeResultFromCache就是通过key获取缓存,decodeSourceFromCache()就是通过orginKey获取缓存。 private Resource<Z> transformEncodeAndTranscode(Resource<T> decoded)
处理和包装资源;缓存资源。 //保存原资源
 private Resource<T> cacheAndDecodeSourceData(A data) throws IOException   //保存处理后的资源
 private void writeTransformedToCache(Resource<T> transformed)

3.11 Transformation

  1. Resource<T> transform(Resource<T> resource, int outWidth, int outHeight);

        处理资源,这里面出现BitmapPool类,达到Bitmap复用。

3.12 ResourceDecoder

        用于将文件、IO流转化为Resource

3.13BitmapPool

        用于存放从LruCache中remove的Bitmap, 用于后面创建Bitmap时候的重复利用。

Glide使用

        由于篇幅过长,可以点击“阅读原文”查看更多内容。

你有好的文章想和大家分享欢迎投稿,直接向我投递文章链接即可


Java和Android架构

微信扫描或者点击下方二维码领取Android\Python\AI\Java等高级进阶资源

关注后回复“百度”、“阿里”、“腾讯”、“资源”有惊喜

公众号:JANiubility

欢迎加入我们的Java和Android架构圈,已有近1000人加入学习交流,更多学习资源更新,更多交流进步


更多学习资料点击下面的“阅读原文”获取

Android图片框架Glide-3.7.0(最新,很强大),超好用的图片框架(包含jar和源码Glide 是一个高效、开源、 Android设备上的媒体管理框架,它遵循BSD、MIT以及Apache 2.0协议发布。Glide具有获取、解码和展示视频剧照、图片、动画等功能,它还有灵活的API,这些API使开发者能够将Glide应用在几乎任何网络协议栈里。创建Glide的主要目的有两个,一个是实现平滑的图片列表滚动效果,另一个是支持远程图片的获取、大小调整和展示。近日,Glide 3.0发布,现已提供 jar包下载 ,同时还支持使用Gradle以及Maven进行构建。该版本包括很多值得关注的新功能,如支持Gif 动画和视频剧照解码、智能的暂停和重新开始请求、支持缩略图等,具体新增功能如下如下: GIF 动画的解码 :通过调用Glide.with(context).load(“图片路径“)方法,GIF动画图片可以自动显示为动画效果。如果想有更多的控制,还可以使用Glide.with(context).load(“图片路径“).asBitmap()方法加载静态图片,使用Glide.with(context).load(“图片路径“).asGif()方法加载动画图片 本地视频剧照的解码: 通过调用Glide.with(context).load(“图片路径“)方法,Glide能够支持Android设备中的所有视频剧照的加载和展示 缩略图的支持: 为了减少在同一个view组件里同时加载多张图片的时间,可以调用Glide.with(context).load(“图片路径“).thumbnail(“缩略比例“).into(“view组件“)方法加载一个缩略图,还可以控制thumbnail()中的参数的大小,以控制显示不同比例大小的缩略图 Activity 生命周期的集成: 当Activity暂停和重启时,Glide能够做到智能的暂停和重新开始请求,并且当Android设备的连接状态变化时,所有失败的请求能够自动重新请求 转码的支持: Glide的toBytes() 和transcode() 两个方法可以用来获取、解码和变换背景图片,并且transcode() 方法还能够改变图片的样式 动画的支持: 新增支持图片的淡入淡出动画效果(调用crossFade()方法)和查看动画的属性的功能 OkHttp 和Volley 的支持: 默认选择HttpUrlConnection作为网络协议栈,还可以选择OkHttp和Volley作为网络协议栈 其他功能: 如在图片加载过程中,使用Drawables对象作为占位符、图片请求的优化、图片的宽度和高度可重新设定、缩略图和原图的缓存等功能
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值