zoukankan      html  css  js  c++  java
  • Android 图片加载框架Glide4.0源码完全解析(一)

    写在之前

    上一篇博文写的是Picasso基本使用和源码完全解析,Picasso的源码阅读起来还是很顺畅的,然后就想到Glide框架,网上大家也都推荐使用这个框架用来加载图片,正好我目前的写作目标也是分析当前一些流行的框架源码,那就也来解析下Glide的源码吧,而且有了Picasso源码的分析相信很快就搞定Glide的,结果也就悲剧了,深陷其中无法自拔了,Glide的源码远非Picasso能比,阅读起来也是相当的困难的,而且我使用的是最新的Glide4.0,与之前版本有较大的差异,网上也没可以参考的资料,这就悲剧了,苦头专研呗。直到今天才从深沟中冒出头了,差点憋死,哈哈。

    正文

    Glide的使用和Picasso基本一样,这里就不再多说,主要是因为源码分析会写的很长很细,再加上基本使用的话,就更加长了,而且上一篇已写过Picasso的基本使用,这两者在使用方面相差的微乎及微,所以我们这篇文章直接进入源码分析。

    Glide 源码分析

    首先在build.gradle里添加如下引用:

    compile 'com.github.bumptech.glide:glide:4.0.0-RC0'
    

    这里我用的是Glide4.0也是最新的版本,和3.X在源码上还是有很大的差别的。看过3.X源码的相信对比下这篇文章就会知道。

    ok,和Picasso的分析模式一样,我们也是从下面最简单的代码进行一步一步的深入分析:

    Glide.with(MainActivity.this).load(url).into(headerImage);
    

    with()

    首先我们来看看当我们调用Glide的with方法那做了哪些工作:

    with方法中可以接受Context,Activity,FragmentActivity,Fragment甚至是View不同的类型,返回的是RequestManager对象,这个对象是需要在RequestManagerRetriever中获取的,那我们在来看看RequestManagerRetriever是怎么获取到的?请看getRetriever方法的源码:

    getRetriever方法中也没有真正的创建RequestManagerRetriever对象,而是从Glide的getRequestManagerRetriever方法中获取,那么很明显的可以看出所做的工作都是在Glide的get方法中完成的,在来看下get方法源码:

    来到这一步,我们看到了非常熟悉的代码设计原理,那就是双重加锁的单例模式保证Glide对象的唯一性,那么initGlide就是创建Glide对象的方法了,请看:

    这是initGlide方法中最重要的代码,主要是创建了一个GlideBuilder对象,然后调用build方法来完成Glide对象的创建,相信不用看bulid方法,大家也会猜到接下来将要发生什么样的事情,没错,那就是使用建造者设计模式来完美的构建出Glide对象:

    public Glide build(Context context) {
        if (sourceExecutor == null) {
          sourceExecutor = GlideExecutor.newSourceExecutor();
        }
    
        if (diskCacheExecutor == null) {
          diskCacheExecutor = GlideExecutor.newDiskCacheExecutor();
        }
    
        if (memorySizeCalculator == null) {
          memorySizeCalculator = new MemorySizeCalculator.Builder(context).build();
        }
    
        if (connectivityMonitorFactory == null) {
          connectivityMonitorFactory = new DefaultConnectivityMonitorFactory();
        }
    
        if (bitmapPool == null) {
          int size = memorySizeCalculator.getBitmapPoolSize();
          bitmapPool = new LruBitmapPool(size);
        }
    
        if (arrayPool == null) {
          arrayPool = new LruArrayPool(memorySizeCalculator.getArrayPoolSizeInBytes());
        }
    
        if (memoryCache == null) {
          memoryCache = new LruResourceCache(memorySizeCalculator.getMemoryCacheSize());
        }
    
        if (diskCacheFactory == null) {
          diskCacheFactory = new InternalCacheDiskCacheFactory(context);
        }
    
        if (engine == null) {
          engine = new Engine(memoryCache, diskCacheFactory, diskCacheExecutor, sourceExecutor,
              GlideExecutor.newUnlimitedSourceExecutor());
        }
    
        RequestManagerRetriever requestManagerRetriever = new RequestManagerRetriever(
            requestManagerFactory);
    
        return new Glide(
            context,
            engine,
            memoryCache,
            bitmapPool,
            arrayPool,
            requestManagerRetriever,
            connectivityMonitorFactory,
            logLevel,
            defaultRequestOptions.lock());
      }
    

    build方法中主要是构建线程池(包括sourceExecutor ,diskCacheExecutor ),缓存大小和缓存器,默认的连接监听工厂(connectivityMonitorFactory ),Engine对象和RequestManagerRetriever 对象等等。

    有几个重要的对象创建,我们这里先看下它的构建内容:

    1 Engine对象

    创建Engine对象在构造方法中传递了几个重要的参数,分别是线程池,内存缓存和硬盘缓存对象,那我们来看看在构造方法中它是怎么构建Engine对象的:

    Engine(MemoryCache cache,
          DiskCache.Factory diskCacheFactory,
          GlideExecutor diskCacheExecutor,
          GlideExecutor sourceExecutor,
          GlideExecutor sourceUnlimitedExecutor,
          Map<Key, EngineJob<?>> jobs,
          EngineKeyFactory keyFactory,
          Map<Key, WeakReference<EngineResource<?>>> activeResources,
          EngineJobFactory engineJobFactory,
          DecodeJobFactory decodeJobFactory,
          ResourceRecycler resourceRecycler) {
        this.cache = cache;
        this.diskCacheProvider = new LazyDiskCacheProvider(diskCacheFactory);
    
        if (activeResources == null) {
          activeResources = new HashMap<>();
        }
        this.activeResources = activeResources;
    
        if (keyFactory == null) {
          keyFactory = new EngineKeyFactory();
        }
        this.keyFactory = keyFactory;
    
        if (jobs == null) {
          jobs = new HashMap<>();
        }
        this.jobs = jobs;
    
        if (engineJobFactory == null) {
          engineJobFactory = new EngineJobFactory(diskCacheExecutor, sourceExecutor,
              sourceUnlimitedExecutor, this);
        }
        this.engineJobFactory = engineJobFactory;
    
        if (decodeJobFactory == null) {
          decodeJobFactory = new DecodeJobFactory(diskCacheProvider);
        }
        this.decodeJobFactory = decodeJobFactory;
    
        if (resourceRecycler == null) {
          resourceRecycler = new ResourceRecycler();
        }
        this.resourceRecycler = resourceRecycler;
    
        cache.setResourceRemovedListener(this);
      }
    

    创建了几个工厂对象方法,比如EngineKeyFactory,EngineJobFactory和DecodeJobFactory,几个HashMap类型的对象集合,如:jobs ,activeResources 等等,然后就分别把这些对象赋值给Engine的成员变量,那么来看下创建Engine对象时到底初始化了那些成员变量:

    ok,Engine是一个非常重要的对象,后面扮演着重要的角色,为了方面理解它所拥有那些可使用的对象,这里我做了个类图显示的标了出来。

    2 RequestManagerRetriever 对象

    再来看看RequestManagerRetriever 对象的创建,这个相对的简单很多,我们来看下它的构造方法:

    由于我们传递过来的requestManagerFactory为空,所以factory将会使用默认的DEFAULT_FACTORY工厂,DEFAULT_FACTORY是真正创建RequestManager对象的地方,稍后介绍。

    这里只是让大家知道这里的factory就是DEFAULT_FACTORY。

    来看看它拥有哪些成员:

    3 Glide对象

    在build方法中 return new Gilde(),创建一个Glide对象并返回,那在Gilde构造方法中做了哪些初始化工作呢?

    Glide(
          Context context,
          Engine engine,
          MemoryCache memoryCache,
          BitmapPool bitmapPool,
          ArrayPool arrayPool,
          RequestManagerRetriever requestManagerRetriever,
          ConnectivityMonitorFactory connectivityMonitorFactory,
          int logLevel,
          RequestOptions defaultRequestOptions) {
        this.engine = engine;
        this.bitmapPool = bitmapPool;
        this.arrayPool = arrayPool;
        this.memoryCache = memoryCache;
        this.requestManagerRetriever = requestManagerRetriever;
        this.connectivityMonitorFactory = connectivityMonitorFactory;
    
        DecodeFormat decodeFormat = defaultRequestOptions.getOptions().get(Downsampler.DECODE_FORMAT);
        bitmapPreFiller = new BitmapPreFiller(memoryCache, bitmapPool, decodeFormat);
    
        final Resources resources = context.getResources();
    
        registry = new Registry();
        registry.register(new DefaultImageHeaderParser());
    
    	registry.register()...append()...
    
        ImageViewTargetFactory imageViewTargetFactory = new ImageViewTargetFactory();
        glideContext = new GlideContext(context, registry, imageViewTargetFactory,
            defaultRequestOptions, engine, this, logLevel);
      }
    

    这里首先是把传递进来的参数赋值给成员变量,然后创建了几个重要的对象:

    ①:Registry对象

    Registry主要是添加很多的注册或解析方式等,这在后面用来解析是从内存,文件或是网络获取资源有着重要的作用,而且它每一类解析方式都会提供多个方法,一种方式获取不到将会使用另外一种,知道获取到资源为止,来看下它的register和append方法:

    主要是存放到不同的对象中的集合变量中。

    ②:GlideContext对象

    GlideContext对象在后面也扮演中重要的角色,创建这个对象到目前为止只是为了初始化和赋值:

    总结下Glide,Registry和GlideContext对象所初始化的参数:

    这是到目前对象所拥有的成员方法和成员变量。

    ok,再回到上面build方法,在返回Glide对象后,调用getRequestManagerRetriever()从而获取到RequestManagerRetriever对象,从上面Glide类图我们也可以看出,Glide对象已包含RequestManagerRetriever对象。

    再往上返回一步,在getRetriever(activity)方法中获取到RequestManagerRetriever对象后,调用get(activity)来获取RequestManager对象,那么我们来看看它是怎么获取到的?

    首先判断是否在子线程执行,否则就调用supportFragmentGet方法来获取RequestManager对象,那么来看下它的源码:

    还记得我们的RequestManagerRetriever拥有哪些成员吗,不记得就去看看上面它的类图吧,由它的源码我们可以看到它将会使用factory并调用它的build方法,还记得factory是什么吗?上面已分析factory就是DEFAULT_FACTORY,那来看看它的源码实现:

    在build中创建一个RequestManager对象并返回,来看下RequestManager的构造方法中做了哪些操作:

     RequestManager(
          Glide glide,
          Lifecycle lifecycle,
          RequestManagerTreeNode treeNode,
          RequestTracker requestTracker,
          ConnectivityMonitorFactory factory) {
        this.glide = glide;
        this.lifecycle = lifecycle;
        this.treeNode = treeNode;
        this.requestTracker = requestTracker;
    
        final Context context = glide.getGlideContext().getBaseContext();
    
        connectivityMonitor =
            factory.build(context, new RequestManagerConnectivityListener(requestTracker));
    
        if (Util.isOnBackgroundThread()) {
          mainHandler.post(addSelfToLifecycle);
        } else {
          lifecycle.addListener(this);
        }
        lifecycle.addListener(connectivityMonitor);
    
        setRequestOptions(glide.getGlideContext().getDefaultRequestOptions());
    
        glide.registerRequestManager(this);
      }
    

    主要是赋值,添加生命周期监听器,设置请求属性,以及注册请求管理器,代码还是很简单的,都能看的明白。

    来看下它的类图:

    ok,到此,我们的with方法中获取RequestManager对象就已完成。

    来看下with方法执行的顺序图:

    注:流程图看不清楚,可以选择在“新标签中打开图片”查看。

    load()

    在调用with方法获取到RequestManager对象的前提下,调用load方法,并传递我们的url参数,来看下它的源码:

    这里并没有直接的去加载我们的url获取资源,而是首先调用asDrawable方法来配置图片的信息,其实就是说加载获取的图片资源是转换为drawale或是bitmap或是gif进行图片显示,默认的是使用drawale,你也可以使用asGif()/asBitmap()来设置它是已什么形式来展示。这里我们按默认的方式来分析。

    load方法目的是为了获取RequestBuilder对象,下面来一步步分解它源码:

    首先来看下asDrawable()的源码:

    asDrawable()中首先调用as方法,并传进Drawable.class作为参数,来看下as方法的源码:

    由as方法,我们可看到它直接的创建一个RequestBuilder对象,并传递了相关的参数进去,这里要注意下resourceClass就是Drawable.class这里在后面有个选择分支时使用到。

    来看下RequestBuilder的构造方法中做了哪些初始化布局。

    很简单的赋值,这里也需要注意的是transcodeClass就是Drawable.class类。

    ok,获取到RequestBuilder对象后,它又做了进一步的赋值操作,就是在transition方法中,

    把创建的DrawableTransitionOptions对象赋值给transitionOptions变量。

    ok,再往上来看,完成asDrawable方法对RequestBuilder的创建后才调用load方法来传递我们的url地址,其实在load也没有做什么事,就是一个中转站,转给了loadGeneric方法,来看:

    在loadGeneric方法中也没做其他太多的操作,也是保存了我们的url并且isModelSet设置为true,意思就是说Model已有设置了。来看下它的类图:

    它到目前为止所包含的成员变量和方法都在此。

    ok,到此我们的load方法也分析完毕,来看下它的流程图:

    注:流程图看不清楚,可以选择在“新标签中打开图片”查看。

    由于Glide源码很是复杂,写的很长,所以只能分两篇来发布,第一篇分析了Glide的with和load方法源码,第二篇将会分析into方法,说实在的into方法复杂程度远超过with和load方法总和,但是没关系,还是保持一贯的风格,一步步的分析其执行流程,相信大家学完肯定能完全的掌握它的源码结构。

    ok,今天就先发布这一篇吧。

    各位如果还有哪里不明白的,或是我这里讲的还不够透彻,亦或是讲错了的地方请留言指正,让我们共同进步,谢谢

    同时,请大家扫一扫关注我的微信公众号,虽然写的不是很勤,但是每一篇都有质量保证,让您学习到真正的知识。

    关注我的微信公众号

  • 相关阅读:
    EJB
    Token
    FreeMarker
    solr
    maven学习四:maven集成jetty插件发布web项目 标签: maven
    代码生成器
    springIOplatform
    数据连接池
    freeMark模板引擎
    张萌作品集
  • 原文地址:https://www.cnblogs.com/guanmanman/p/7008259.html
Copyright © 2011-2022 走看看