android 对glide封装,Android Glide浅析

目前在android项目上,图片加载库有很多选择,Glide是主流的加载库之一,作为一个被google推荐的开源库,它有着跟随页面周期、支持gif和webp、支持多种数据源等特点,并且使用起来很简单,本篇文章将会分析Glide的加载流程,但是Glide的源码比较复杂,我将从Glide的最简单使用分析Glide是如何去加载一张图片的。

(一)从Glide.with(context)入手

Glide.with(context).load(url).asBitmap().into(imageView);

通常,这将是最简单的使用Glide的方式,那么首先我们进入Glide这个类看看:

36092fe62637

glide的with方法

Glide.wth(context)会返回一个RequestManager对象,我们发现Glide重载了多个with方法,返回值都是去调用RequestManagerRetriever.get()方法:

36092fe62637

glide的get方法

RequestManagerRetriever类中会对context加以区分后走对应的get方法,首先判断如果不是主线程,则用ApplicationContext调用get方法:

36092fe62637

通用的get方法

36092fe62637

getApplicationManager

直接new了一个RequestManager对象,将Appcation级别的信息传递了进入,那么如果是在主线程调用,无论context是fragment还是activtiy,最后都会走fragmentGet和supportFragmentGet这两个方法:

36092fe62637

获取fragment

这两个方法都是向当前页面添加一个fragment,一个是添加v4包的,一个是添加android.app.Fragment,我们从fragmentGet看起,首先通过getRequestManagerFragment获得了一个RequestManagerFragment对象:

36092fe62637

配置requestManager

很简单,先从缓存里找,没有就new一个再添加上去。

回到fragmentGet,接着从改fragment中获取RequestManager,因为是才new的,所以RequestManager为空,那么接着new了RequestManagert同时将fragment的lifecycle对象传递进去,set给fragment后返回了manager。

因为Glide.wth(context)最后就是返回了一个RequestManagert对象,所以这一步到这里结束了,那添加的这个fragment有什么用呢,我们分别打开RequestManagerFragment和RequestManager看看:

36092fe62637

RequestManagerFragment部分代码

36092fe62637

RequestManagerFragment部分代码

可以看到RequestManagerFragment在初始化的时候创建了一个ActivityFragmentLifecycle对象,在下面三个生命周期的时候分别调用了ActivityFragmentLifecycle对应的方法。

36092fe62637

RequestManager部分代码

在RequestManager的构造方法中,最后传进来的lifecycle分别add(this)和addListener(connectivityMonitor),所以当RequestManagerFragment对应周期调用时,RequestManager也会调用对应方法,其实光看类名我们就能明白RequestManager是对每个ImageRequest进行管理的类,那么这样一来,每个ImageRequest就和Fragment的生命周期同步,所以Glide是这样做到请求与页面周期同步的。我们再来看看具体是如何管理的以及加入的connectivityMonitor的作用:

36092fe62637

RequestManager部分代码

RequestManager的三个方法中,最后都是调用requestTracker的方法,所以requestTracker是最后的request容器。再看看最开始的lifecycle.addListener(connectivityMonitor),它由ConnectivityMonitor connectivityMonitor = factory.build(context,   new RequestManagerConnectivityListener(requestTracker)),构造而来,也将requestTracker传递了进去:

36092fe62637

ConnectivityMonitorFactory

加载图片自然是要联网了,进入DefaultConnectivityMonitor看看:

36092fe62637

DefaultConnectivityMonitor简化代码

36092fe62637

DefaultConnectivityMonitor简化代码

36092fe62637

DefaultConnectivityMonitor简化代码

既然它被lifecycle添加进去了,那么一定有对的几个方法,这个类其实主要是注册了一个广播去监听网络状况,当网络状况变化的时候调用listener.onConnectivityChanged(isConnected),这个listener就是一开始传递进来的RequestManagerConnectivityListener了:

36092fe62637

RequestManagerConnectivityListener

所以最终的作用其实是在网络重连的时候重启request,那么Glide.with(context)的主要流程我们就走完了。

一张图总结如下

36092fe62637

fragment与request周期管理

(二)load()和asBitmap()

在with()方法之后将返回RequestManager对象,那么接着我们直接去RequestManager的load(String)方法看看:

36092fe62637

RequestManager相关方法

36092fe62637

RequestManager相关方法

追着流程下去最后是进入了loadGeneric(Class modelClass)方法,该方法首先生成了两个ModelLoader对象,然后将这两个对象合着其他的内容传入了一个新的DrawableTypeRequest对象中,虽然最后的返回还调用了optionsApplier.apply(),但是我们知道Glide.with(context).load(url)返回的就是一个DrawableTypeRequest对象,所以我们大概可以判断最后就是返回这个新生成的DrawableTypeRequest对象了。

这里的两个ModelLoader生成过程太过复杂就不分析,我们直接跟着主流程走下去

36092fe62637

debug

但是我们可以通过断点知道这里获得的两个对象是StreamStringLoader和FileDescriptorStringLoader,接着我们看看optionsApplier是什么:

36092fe62637

RequestManager的构造方法

在RequestManager的构造方法中optionsApplier由new了一个新的OptionsApplier对象赋值,那么我们看看OptionsApplier的apply方法:

36092fe62637

OptionsApplier

36092fe62637

debug

调用options.apply之后就把传入的对象返回了,这个options我们从来没有设置过,同时在debug中它也确实为空,那么确实和我们猜测的一样,loadGeneric()中直接返回了new的DrawableTypeRequest对象,紧接着调用了它的load方法:

36092fe62637

DrawableTypeRequest继承关系

36092fe62637

DrawableRequestBuilder

36092fe62637

GenericRequestBuilder

可见load方法只是对model赋值,这里传入的model就是url,最后返回本身,那么Glide.with(context).load(url)也走完了,接着我们来看DrawableRequestBuilder的asBitmap()方法

36092fe62637

asBitmap()

生成了一个BitmapTypeRequest对象并将DrawableRequestBuilder的相关配置传入且返回,所以整个Glide.with(context).load(url).asBitmap()还是比较清楚的,最后返回了一个BitmapTypeRequest对象

(三)复杂的into()

讲完了前几个步骤现在只剩下最后的的into()方法了,目前的几个步骤只是传递了参数,但是实际的图片请求毛都没见着,所以你应该可以预计into()方法做的事很多了,into()方法是在BitmapTypeRequest父类中实现的:

36092fe62637

BitmapTypeRequest继承关系

36092fe62637

into()方法

我们并没有做scaleType的配置,接着看glide.buildImageViewTarget(view, transcodeClass)

36092fe62637

buildImageViewTarget

36092fe62637

Glide类

在Glide类中很清楚发现接着该找ImageViewTargetFactory.buildTarget()

36092fe62637

ImageViewTargetFactory

ImageViewTargetFactory代码很简单,是作为一个工具类使用的,根据传递的class生成对应的ImageViewTarget,根据我们调用的Glide.with(context).load(url).asBitmap()其实我们可以猜测这里的clazz是Bitmap.class,我们还是去理一理怎么来的:

36092fe62637

into()方法

36092fe62637

GenericRequestBuilder构造方法

36092fe62637

BitmapTypeRequest构造方法

看了构造方法我们可以发现BitmapTypeRequest确实传递了Bitmap.class进去,那么into()方法的传递参数是一个BitmapImageViewTarget对象

36092fe62637

into()方法

在接下来into()方法中首先从target中取出之前的request,将之前的request回收掉,接着调用buildRequest(target)创建了一个新的request添加到requestTracker中,并且将target添加到lifecycle中,这列lifecycle对象就是一开始的ActivityFragmentLifecycle,那么这个request也将会跟着一开始添加的fragment生命周期运行了。在RequestTracker中,运行request其实是调用request.begin(),那么我们进入buildRequest(target)找找看生成的request这个方法是做了什么:

36092fe62637

buildRequest相关方法

thumbnail相关是设置略缩图的,这里我们不用管,直接去看obtainRequest(target, sizeMultiplier, priority, parentCoordinator)

36092fe62637

obtainRequest()方法

36092fe62637

GenericRequest.obtain()方法

追踪下去可以看到最后生成的是GenericRequest对象,再接着看看begin()方法:

36092fe62637

begin()方法

我们先看下面的代码:

36092fe62637

begin()方法部分代码

如果是在正常状态,那么就调用target.onLoadStarted,那么我们回到BitmapImageViewTarget,onLoadStarted是在父类ImageViewTarget里重写的,我们看看干了什么:

36092fe62637

ImageViewTarget.onLoadStarted()

所以是将我们传递给into()方法的ImageView设置了一张图片,原来我们在使用glide设置placeHolder图片就是在这个时候设置进来的了。再回到begin()方法,最上面是设置erorHolder的方法,只要model等于空,同样的设置错误站位图,这个model是什么呢,还记得我们在分析Glide.with().load()方法的源码吗:

36092fe62637

RequestManager.load()

36092fe62637

GenericRequestBuilder.load()

传入的url最后传递给model,而这个model最后在生成GenericRequest的时候又传递给了它:

36092fe62637

obtainRequest()生成GenericRequest

所以加载之前的判断条件是url是不是为空,为空则为异常。

回到begin()方法,上面是异常,下面是默认展位图,那么中间就是加载图片的部分了:

36092fe62637

begin()方法部分代码

Util.isValidDimensions判断是否设置了有效的overrideWidth和overrideHeight,我们没有设置过直接走else,target是BitmapImageViewTarget,在它的父类ViewTarget中实现了getSize()方法:

36092fe62637

ViewTarget.getSize()

36092fe62637

ViewTarget构造方法

36092fe62637

SizeDetermine.getSize()

依次追下去,我们发现最后调用的SizeDetermine.getSize(),currentWidth和currentHeight是展示加载的图片的ImageView的有效宽高,通常都可以获取到,那么我们直接去看cb.onSizeReady(currentWidth, currentHeight),这里传进来的cb也就是GenericRequest本身了。

36092fe62637

GenericRequest.onSizeReady()

ImageView的宽高进来之后,计算了一个设置的宽高,因为默认sizeMultiplier是为1的,如果没有设置过sizeMultiplier默认设置宽高即为ImageView的宽高,之后的modelLoader和dataFetcher又得绕回去了,我们回去看看DrawableTypeRequest的构造方法:

36092fe62637

DrawableTypeRequest相关方法

在DrawableTypeRequest的构造方法中调用了super构造方法,其中第三个参数传递了一个LoadProvider,这个provider就是之后传递到GenericRequest的loadProvider对象,buildProvider()方法一起贴出来了,返回了一个FixedLoadProvider对象,我们进入FixedLoadProvider发现getModelLoader返回的就是构造时传入的ImageVideoModelLoader对象,并且getTranscoder返回的也是构造时传递的transcoder,

36092fe62637

FixedLoadProvider部分代码

我们跟着glide.buildTranscoder(resourceClass, transcodedClass)的流程,看看transcoder是什么:

36092fe62637

glide.buildTranscoder()

36092fe62637

transcoderRegistry.get()

我们知道传递进来的decodedClass和transcodedClass分别是GifBitmapWrapper.class和GlideDrawable.class,那么这里最后会由factories.get(GET_KEY)返回结果,而在Glide类的构造方法中有一句这样的初始化代码:

36092fe62637

Glide构造函数部分代码

在这里注册了GifBitmapWrapperDrawableTranscoder,那么最后返回就是GifBitmapWrapperDrawableTranscoder了,

回到onSizeReady()方法,这些参数和其他一些配置都一起传递给了engine.load(),那我们找下engine是如何生成的:

36092fe62637

GenericRequestBuilder.obtainRequest()

GenericRequestBuilder.obtainRequest()在创建GenericRequest的时候获取了glide的engine对象传递了进去,而glide初始化是通过GlideBuilder完成的:

36092fe62637

GlideBuilder.createGlide()

在创建engine的时候,将cache和线程相关传递进去了,那么我们可以确定,图片的加载最后是交给engine处理了:

36092fe62637

Engine.load()方法

在这个方法中首先根据配置生成了对应的key,之后是获取缓存的操作,我们先不看,因为还不知道是如何设置缓存的,我们直接看最下面的几段代码,首先根据key创建了一个EngineJob对象,其次根据配置选项创建了一个DecodeJob对象,随后将他们传入了一个EngineRunnable对象中,那么加载图片就是在这个runnable中执行了,调用了engineJob.start(runnable)之后就开始加载图片:

36092fe62637

EngineRunnable.run()

36092fe62637

EngineRunnable.decode()

加载图片是通过decode()方法进行了,这里判断了是否要走缓存,我们直接不看缓存直接走decodeFromSource(),虽然EngineRunnable默认是走一次缓存的,但是第一次加载是没有缓存的,最后还是走decodeFromSource()

36092fe62637

EngineRunnable.decodeFromSource()

36092fe62637

DecodeJob.decodeSource()

在DecodeJob中decodeSource()首先通过fetcher.loadData()获取data,这个fetcher是啥呢,我们重新回顾下DecodeJob的生成:

36092fe62637

GenericRequest.onSizeReady()部分代码

36092fe62637

Engine.load()部分方法

fetcher是这么传进来的,loadProvider.getModelLoader()返回的是ImageVideoModelLoader:

36092fe62637

ImageVideoModelLoader.getResourceFetcher()

所以这里最后返回了一个ImageVideoModelLoader对象

36092fe62637

ImageVideoFetcher.loadData()

随后进入了loadData()方法,其实在这里fileDescriptor获取为空,这是因为最开始初始化的原因,也是我一开始说的StreamStringLoader和FileDescriptorStringLoader生成太过复杂,我们只走主流程,streamFethcer是个OkHttpStreamFetcher对象,那么我们看看它的loadData()方法:

36092fe62637

OkHttpStreamFetcher.loadData()

从OkHttpStreamFetcher名字可以看出,我所使用的这个版本的Glide是使用okhttp去加载图片,确实loadData里也是使用okhttp去加载的

36092fe62637

OkHttpUrlLoader$Factory.getInternalClient()

在OkHttpUrlLoader$Factory中确实也初始化了OkHttpClient

回到ImageVideoModelLoader,fetcher.loadData()返回的内容会封装在ImageVideoWrapper对象中回到DecodeJob返回,接着会把他传递到decodeFromSourceData()处理:

36092fe62637

decodeFromSourceData()

我们没有做过磁盘缓存的配置,直接进入else判断,首先我们看loadProvider.getSourceDecoder()是什么:

36092fe62637

loadProvider.getSourceDecoder()

这里的dataLoadProvider是初始化的时候传入的:

36092fe62637

FixedLoadProvider初始化

36092fe62637

DataLoadProviderRegistry生成DataLoadProvider

36092fe62637

Glide初始化

由上面的步骤可知,根据FixedLoadProvider初始化出入的class,生成的是ImageVideoGifDrawableLoadProvider对象,而ImageVideoGifDrawableLoadProvider.getSourceDecoder()则返回GifBitmapWrapperResourceDecoder:

36092fe62637

ImageVideoGifDrawableLoadProvider初始化

那么接着看GifBitmapWrapperResourceDecoder.decode():

36092fe62637

decode()

36092fe62637

decode()

36092fe62637

decodeStream()

36092fe62637

decodeBitmapWrapper()

GifBitmapWrapperResourceDecode的流程比较清楚,由于我们设置的是bitmap,按照流程下去最后会在decodeBitmapWrapper()返回了一个GifBitmapWrapper对象,这里还需要看看bitmapDecoder.decode(toDecode, width, height),虽然后面经过的类比较多,但是其实都只提供了一个方法去实现功能,那么这里我直接断点跟着流程进去了:

36092fe62637

ImageVideoBitmapDecoder

bitmapDecoder是一个ImageVideoBitmapDecoder对象,其中又调用了streamDecoder.decode(is, width, height):

36092fe62637

StreamBitmapDecoder

StreamBitmapDecoder再调用了downsampler.decode(source, bitmapPool, width, height, decodeFormat):

36092fe62637

downsampler部分代码

Downsampler类中最后生成的bitmap就是调用BitmapFactory.decodeStream()获得的,这个bitmap会被封装进Resource对象返回,最后封装成回到EngineRunnable.run()返回,并传入onLoadComplete():

36092fe62637

EngineRunnable.run()

这个结果会回传到EngineJob通过handler回调至handleResultOnMainThread()方法:

36092fe62637

EngineJob.handleResultOnMainThread()

在这个方法中又将结果通过ResourceCallback回传,而在Engine.load()方法中我们将之前的GenericRequest添加进cbs了,所以这里又会回到GenericRequest:

36092fe62637

Engine.load()

36092fe62637

GenericRequest.onResourceReady()

在onResourceReady()方法中调用了target.onResourceReady(result, animation),还记得我们在调用into(ImageView)方法时ImageView被封装进了BitmapImageViewTarget吗,这里的target就是它了,:

36092fe62637

BitmapImageViewTarget.setResource()

终于,到这里图片被加载下来并设置上view了!

回头看看Engine.load()中之前遗留下来的的东西:

36092fe62637

Engine.load()

这三个处理分别从cache、activeResources、jobs去取内容,我们在获取到bitmap传递内容的时候封装的Resource对象会又被封装进EngineResource在Engine之间传递,在EngineResource中有个释放资源的方法,里面的listener就是Engine:

36092fe62637

EngineResource.release()

36092fe62637

Engine.onResourceReleased()

也就是在释放资源的时候内存中做了缓存,而activeResources是保存当前活跃的Resource,分别会在Complete()和获取cache的时候保存Resource,Released()的时候移除Resource:

36092fe62637

保存Resource

36092fe62637

保存Resource

36092fe62637

移除Resource

jobs也类似,在任务完成或者取消的时候会移除job,如果发起的任务已有就不重复发起:

36092fe62637

移除job时机

现在看来,Glide.with(context).load(url).asBitmap().into(imageView)这一行代码居然做了这么多的操作,而且我们还只是走了主线,但是其中很多的技巧已经很值得让人学习了。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值