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,今天就先发布这一篇吧。
各位如果还有哪里不明白的,或是我这里讲的还不够透彻,亦或是讲错了的地方请留言指正,让我们共同进步,谢谢
同时,请大家扫一扫关注我的微信公众号,虽然写的不是很勤,但是每一篇都有质量保证,让您学习到真正的知识。