详谈高大上的图片加载框架Glide -源码篇

在上篇文章中,我们介绍了Glide图片加载框架的使用,通过之前的学习,我们可能已经能熟练的将Glide图片加载框架运用到我们的项目中,但是如果有人问你它是如何加载,工作原理是怎样的?为什么自定义GlideModule只需要在Manifest文件中加入meta-data即可?等等很多加载流程以及使用的注意事项。当然要想搞明白这些问题,就需要我们对Glide源码有个大致的认识,去剖析源码深处的奥秘。

接下来就让我们一起去进入Glide的源码世界,本篇文章分析的是Glide 3.7.0版本。特别提醒,阅读本篇文章之前要对Glide的用法要先有一个了解,可以先阅读上篇文章,详谈高大上的图片加载框架Glide -应用篇

此篇文章是自己学习的一个记录,若对阅读文章的你有一定帮助,很是高兴,当然文章如有不足或者错误的地方,欢迎指正,避免我给其他读者错误引导

如果你阅读过上篇文章,或者你使用过Glide,就知道Glide加载图片的最简单方式就是

那么这篇文章就以这句简单的代码为主线,逐步深入Glide的源码。

Glide.with(context)

Glide有四个静态的重载方法with(),其内部都通过RequestManagerRetriever相应的get重载方法获取一个RequestManager对象。RequestManagerRetriever提供各种重载方法的好处就是可以将Glide的加载请求与Activity/Fragment的生命周期绑定而自动执行请求,暂停操作。

接下来我们拿Activity参数分析Glide请求如何和绑定生命周期自动请求,暂停,以及销毁。

assertNotDestroyed主要断言Activity是否已经Destroyed。若是没有销毁,或者Activity的FragmentManager ,然后通过fragmentGet返回RequestManager。

最终通过getRequestManagerFragment()方法获取一个RequestManagerFragment 对象。

此时我们看到RequestManagerFragment 继承了Fragment.并且在其生命周期onStart(),onStop(),onDestory(),调用了ActivityFragmentLifecycle 相应的方法,ActivityFragmentLifecycle实现了Lifecycle 接口,在其中通过addListener(LifecycleListener listener)回调相应(LifecycleListener的 onStart(),onStop(),onDestory())周期方法。LifecycleListener是监听生命周期时间接口。
再次回到fragmentGet方法里下面一句代码

对于RequestManager类,该类实现了LifecycleListener,如下代码

它将刚创建的fragment的lifeCycle传入,并将RequestManager这个listener添加到lifeCycle中,从而实现绑定。在RequestManager的构造方法里看到了requestTracker,该对象就是跟踪请求取消,重启,完成,失败。RequestManagerFragment 主要是用来连接生命周期方法,RequestManager用来实现生命周期中请求方法,而RequestManagerRetriever绑定了RequestManager。

GlideModule实现

在构造方法中还初始化了通过Glide.get(context);初始化了Glide对象

通过get方法单例方式获取实例,并在初始化时实现了GlideModule配置功能。具体怎么实现的呢?接下来具体分析一下,在初始化时new 了一个ManifestParser对象并且调用了parse()方法返回一个GlideModule类型的List.

在parse()方法中通过getApplicationInfo方法获取metaData信息,若有metaData数据(appInfo.metaData != null),如果metaData的值为GlideModule则调用parseModule(key),方法返回GlideModule并add到返回的List中。

查看parseModule(String className)方法

到此我们看到通过反射的方式获取我们在清单文件中声明的自定义的GlideModule对象。在获取到
GlideModule集合之后,遍历了集合并调用相应的applyOptions和registerComponents方法,而Glide对象的生成是通过GlideBuilder的createGlide方法创建。

看到这都是做的一些初始化操作,并将参数传递到Glide构造方法。对于Glide构造方法做的都是一些默认的初始化操作,可以自己去查看源码,此处不再贴出。

通过上面的分析,你就会理解,为什么之前提到配置信息只需要实现GlideModule接口,重写其中的方法,并再清单文件配置metaData,并且metaData的key是自定义GlideModule的全路径名,value值必须是GlideModule.会明白当我们不想让自定义的GlideModule生效时只需要删除相应的GlideModule。当使用了混淆时为什么要配置…

requestManager.load

对于load方法也是可以接收String,Url,Integer等类型的重载方法,在这里,我们拿String类型参数分析。

返回的是DrawableTypeRequest对象,DrawableTypeRequest继承关系如下

20160918155343574

 

而对于DrawableRequestBuilder类使用的是一个创建者模式,对于常用函数placeholder(),error(),transform等设置都是在此设置,

我们看到最终又调用了父类方法

通过查看父类(GenericRequestBuilder)源码你会发现我们每次调用placeholder(),error()的等这些方法,其实都是给该类中的变量赋值。

经过一系列操作后,最终调用into(imageView)方法来完成图片的最终加载

创建请求

由上面看到最终调用的into方法是

上面都执行都调用了 Util.assertMainThread();判断只能在主线程中执行。(更新View当然需要在主线程),在Glide中Target我们可以理解成View,只是Glide对我们的View做了一层封装。
之后通过buildRequest创建请求对象。

最后调用obtainRequest方法

最终通过GenericRequest.obtain方法创建了

至此请求对象创建成功,在通过buildRequest创建请求成功后,使用了target.setRequest(request);将请求设置到target,并通过addListener将target加入到lifecycle。上面执行了那么多都只是请求创建,请求的执行时通过requestTracker.runRequest(request);开始的。

发送请求

在上面几句代码,我们看到,每次提交请求都将请求加入了一个set中,用它来管理请求,然后通过request的实现类GenericRequest查看begin方法执行的内容

上面有一句!isComplete() && !isFailed() && canNotifyStatusChanged()判断,如果都为真会回调target.onLoadStarted(getPlaceholderDrawable());我们可以看到Target的实现类ImageViewTarget中onLoadStarted的回调执行语句

现在你是不是有一种柳暗花明又一村的感觉,终于明白为什么设置placeHolder后,会在加载前有一个占位图,当然设置加载错误图片占位图的原理也是一样的。只不过回调执行时机不同。

Engine类封装了数据获取的重要入口方法,向request层提供这些API,比如load(), release(), clearDiskCache()等方法

我们看到先根据调用loadFromCache从内存加载,若返回值为空再次从活动的资源中加载,若再次为空查看jobs是否提交过任务,若没有提交则创建EngineRunnable,并将任务提交到engineJob中。我们先看下EngineJob中的start方法

接下来看线程类EngineRunnable的run方法,它是任务执行的入口

DiskLruCache获取数据

之后调用decodeJob类中的decodeResultFromCache

接下来我们分析decodeFromSource方法

在数据获取时先调用DataFetcher的loadData()拉取数据,对于DataFetcher的实现类有好几个,我们拿从url拉取数据为例,也就是HttpUrlFetcher类

看到这终于看到了网络加载请求,我们也可以自定义DataFetcher,从而使用其他网络库,如OkHttp,Volley.

最后我们再看下transformEncodeAndTranscode方法

至此,图片加载流程已经介绍完毕,当然还有很多的地方没有提到,相信如果你在阅读本文的同时,自己跟踪源码会轻松很多,如果自己不跟着源码走的话,可能这篇文章看几遍对Glide原理理解的也是云里雾里,或者说当时看的懂,但是很快就不记得。所以切记自己要跟着源码过一遍。

本篇文章实在是长,能读完本文章也是需要一定毅力的…若文章有不足或者错误的地方,欢迎指正,以防止给其他读者错误引导。

打赏支持我写出更多好文章,谢谢!

打赏作者

打赏支持我写出更多好文章,谢谢!

任选一种支付方式

1 1 收藏 评论

关于作者:Code4Android

简介还没来得及写 :) 个人主页 · 我的文章 · 7 ·    

相关文章

可能感兴趣的话题



直接登录
跳到底部
返回顶部