眨眼之间结业已经3年,可是自己的技术生长视乎没有跟上时间的步伐,趁着51假日,决议来剖析学习一下Glide图片加载结构。
文章计划从下面几个方面来学习剖析Glide。
前语
glide是咱们项目开发中十分常见的一个三方结构,它的功用极端强大它为咱们出来好了图片的加载缓存等功用。运用起来十分便利。那么咱们应该怎么来进行运用呢?它的完结本来又是什么呢?v . b . n
Glide地址: github.com/bump! 7 l v vtech/gl…
Glide官方运用文档: muyangmin.github.io/glide-docs-…
文章glide的运用版本:4.9.7 Z h ! {0
本篇文章首要对glide的加载流程进行剖析。
基本运用
-
简略的加载
//context能够使activity,application,fK k O #ragment //imageUrl为图片地址 //image 需求显现的图片 Glide.with(context).load(imageUk 2 orl).into(image);
-
设置占位图以及加载犯错的图片
Glide.with(c+ , r e Uontext) .load(imageUrl) .placeholder(R.drawable.coordinator_demo) .error(R.drawable.% R P Pcoordinator_demo) .into(image);
上面是咱i j K M q } 5 t们为单个图片的加载设置配置,可是常见的的情况下咱们许多图片的加载除了加载地址和需求显现的ImageView不同其他的都是相同的。难道咱们要为每一个图片的加载都进行设置吗?答案是否定的,glid0 e ? f – ,e为) L w 9 #咱们提供了一个方针:RequestOptions便利咱们共享不同模块的图片加载项。2 L c ; | @ +
val requestOptions = RequestOptions() requestOptions .placeholder(R.drawable.coordinator_d: p ! 7 m h lemo) .error(R.drawable.coor! ! ] g Odinator_demo) Glide.with(context).load(imageUrl).apply(requestOptions).into(image);
RequestOptions方针的创立十分简略,能x s O够直接new一个方针或许经过它的恣意一个静态办法的调用回来RequestOptions方针。
Glide源码剖析
经过给glide的运用咱们发现Glide的图片加载首要运用了三个办法:
- with()
- load()
- into; v P V , – [()
with办法
能够看到抛开废弃的办法Glide有5个重载的with.它们的回来方针都是RequestManager方针的实例。
经过阅读源码咱们发现终究回来的RequestM1 f f R ] Yanager方针是由RequestManagerRetriever的get办法回来的。get()有5个重载办法别离对应Glide的5个重载。咱们来一个一个进行剖析。
-
传递的Context是Application的context.终究调用的是getApplicatio^ ; h ( } z v d :nManager办法。其完结如下:
@NonNull private RequestManager getApplicationManager(@NonNull Context context) { // E( U W L A Mither an application context or we're on a backgrouH ] c M x R g C Pnd thread. if (applicationa E y sManager == null) { synchronized (this) { if (applicatio* V =nManager == null) { // N 7 ~ F # ormally pause/resume is taken care of by the fragment we add to the fragment or // activity. However, in this case since the manager attached to the application will not /S Y 5 n } / j , ?/ receive lifecycle events, we must force the mana: m K Uger to start res% Q Eumed usinS ~ e f i S r : og // ApplicatioV ] L L D j - 1 (nLifecycle. // TODO(b/27524013): Factor out this Glide.geE = O % W 2t() call. Glide glide = Glide.get(context.getApplicationContext()); applicationManaw r n g D W jger = factory.E # D 1 y :build( glide, new Appf 9 S g [ { M * plicationLifecycle(), new EmptyRequestManagerTreeNode(), context.getApplicationL O ) K p ) P e !Context()); } } } return applicationManager; }
这儿经过双重锁的单例来保证针对Applicationx + J p的Context只要一个Requ3 ~ v _ J ?estManager.
-
传入方针是FragmentActivity
@NonNull public RequestManager get(@NonNull FragmentActivity activity) { if (Util.isOnBackgroundThread()) { return get(activity.geI U * U #tApplicationContext()); } else { ass3 6 u & = Q i ?ertNotDestroyed(activity); FragmentManager fm = activity.getSupportFT % wragmentManager(); r% y p | / L W Eeturn supportFragml ! : C * i 1 B 9entGet( activity, fm, /*pareo : W f E ^ntHint=*/ null, isActivityVisible(activity)); }y i 8 Y = }
能够看到上面的代码终究会调用到supportFragmentGet办法,这儿才是真正回来Reque, H 0 K W ustManager的方位。
@NonNull private RequestManager supportFragmentGet( @NonNull Context context, @NonNu& ^ T } _ . g A mll FragmentManager fm, @Nullable. 0 s A p Fragment parentHint, boolean isParentVisible) { SupportRequestManagerFragment current = getSupportRequestManagerFragment(fm, W T _ I # parentHint, isPa% ^ w u g 5 +rentVisibd ) 7 Ele); RequestManager requestManager = current.getRequestManager();) c n * + f U b if (requestManager == null) { // TODO(b/27524013): Factor out this Glide.get() callp b g t e. Glide glide = Glide.get(context); requestManager = factory.build( glide, current.getGlideLifecycle(), current.gg H ) C f = } ,etRequestManage q D 1 U 4 ( |rTreeNode(), conte( v V A :xt); current.setRequestManager(requestManager); } return reqw , q h g * KuestManager; }
因为这篇文章常识粗略的了解Glide的加载咱们先不去深入剖析这个RequestMana1 P F Q + Lger是怎么生成的。
-
传入方针是Fragment
@NonNull p$ # ) public RequestManager get(@NonNull Fragment fragment) { Preconditions.checkNotNull(fragment.getActivity(), "You cannot start a loadD * ? on a fragment before it is attached or after it is destroyed"); if (Util.isOnBackgroundThread()) { return get(fragment.getActivity().getApplicationContext()); } else { FragmentMaB + / 8 C Q ~ Onager fm = fragment.getChildFragmentManager()y i ` B , !; return sup} a 5 yportFragmentq g * 4 I ( N `Get(fragment.getActivity(), fm, fragment, fragment.isVisible()); } }
相同的这儿也是调用的supportFragmentGet来获取RequestManager方针。
这儿咱们不需求过分关注细节只需求知道Glide会依据传入的不同的activity或许Fragment来创立对应的requestM 3 zManager。并与其生命周期进行绑定
load
Glide的with办法回来的是Reque F N * N C [estManager接着咱们看看RequestManagY a $ { ler的load办法。
每一个load都会默许调用asDrae j G } cwable办法。咱们来看4 : Q看它的完结:
public RequestY ! { z ; T }Builder<Drawable> asDrawable() {
return as(Drawable.class);
}
public <ResourceType> ReqZ c : R FuestBuilder<Reso] v H a } ! n rurceType> as(
@NonNull Clas- p 6 O ~ D $s<Res@ q S t E ! R (ourI X g j - DceType> resourceClass) {
return new RequestBuilder<>(glide, this, resourceClass, context);
}
能够看到终究回来了泛型类为Drawable的RequestBuid w )lderv e | 4 ~ 4。在获取到RequestBuilder方{ U E 8 o针后调用了它的load办法。
public RequestBuilder<TranscodeType> load(@Null- . J . e M w H lable String string) {
return lo- ) e A 4 J q madGeneric(string);
}
private RequestBuilder<TranscodeType> loadGen= l m u q $ jeric(@Nullable Objel c e q # 0 p Lct model) {
this.model = modz , O c 4 T lel;
isModelSet = true;
return this;
}
能够看到终究requestManager回来了一个RequestBuild9 } E :er实例方针。除了自动调用requestManager的as办法调用load默许生成的都是RequestBuilder实例方针。m r _ { a
RequestManager和RequestBuilder都完结了ModelTypes接口,Reques) x | *tMa` Y t Mnager的作用是生成限制泛型的RequestBuilder方针。RequestBuilder的作用是配置恳求图片需求的参数。
into
RequestBuiK Q 8 elder的into有多个重载办法,可是他们终究都调用了如下的办法:该办法接收四个参数
Target :方针方针;
RequestLis9 , 2 l ` B I ntener:图片加o C J F 5载监听
BaseRequestOptions:加载图片的配置项
Execuu % T { @ @ 8tor:履行加载图片的线程池
这儿咱们做流程剖析,就不对每个参数的来历做具体的解释了。
private &l{ c g O ^ U St;Y extends Target<TranscodeType>> Y into(
@NonNull Y target,
@Nullable RequestListener<TranscodeType> targetListener,
Baz D [ @ Z ^ 4 p %seRequQ * B T jestOptions<?> options,
Executor callbackExecutor) {
Precondit8 h + ! f F 7ions.checkNotNull(target);
if (!isModelSet) {
throw new IllegalArgumentException("You must call #load() before calling #into()");
}
//构建Request方针
Re[ u E 4 @ . Bquest re? V [ / y qquest = buildRequest(target, tar+ b U Y ` : 0getListener,~ + J 5 b + options, callbackd V 8 J . u f % :Executor);
Request previousT o @ F d = target.getRequest();
if (request.isEquivalentTo(previous)
&& !isSkipMemoryCacheWithCo= I 3 R E S A B DmpletePreviJ I i [ousRequest(options, previous)) {
request.recycle();
// If the request is completed, beg@ X G % l sinning aQ M f 2 M Z l # rgain will en N ] Msure the result is re-delivered,
// triggering RequestListeners and Targets. If the request is failed, beginninP g C Lg again will
// restart thi k 4 me request, givi0 r l a J = I [ Ing it another chance to compleq { }te. If the request is already
// running, we can let it continue running without interruption.
if (!Preconditions.checkNotNull(previous).isRunning()) {
//A o M S b ` R _ c Use6 8 7 the previous requ@ O K West rather than thel L 1 ( # + g m T new one to allow for optimizations lik- P d g r J Je skipping
// setting placeholders, tracking and un-tro W u V packing TarF t 4 ) L L i ! +gets, and obtaining View dimensionU S O 2 o / y 3s
// that are done in the individual Request.
previous.begin();
}
return target;
}
requestManager.clear(target);
target.setRequest(request);
//建议图片加载恳求
requestManager.track(targeth T 4 Y, request);
return target;
}
上面的代码首要做了两件事:构建Request方针;建议图片加载恳求。
在忽略缩略图的情况下终究会运用obtainRequest办法构建Request方针
private Request obtainRequest(
Target<TranscodeType> target,
RequestListener<TranscodeType> targetListener,
BaseRequestOp5 a A & H stions<?I f 9 B 9 ?> requestOptionQ T P M & # Ks,
RequestCoordinator requQ @ & iestCoordinator,
TransitionOptions<?, ? super TranscodeType> transitionOptions,
Priority priority,
int overrideWidth,
int overrideHeight,
Executor caJ N n &llbackExecutor) {
return SingleRequest.obt] f e Z , + Bain(
con $ D W p itext,
glideContext,
model,
transcodeClass,
requestOptions,
o; d gverrideWidth,
overrideHeight,
priority,
targJ m { m [ R let,
targetListener,
requestListeners,
requestCoordinator,
glideContext.getEngine(),
tran! . E F C ssitionOptions.getTransitionFactory(),
callbackExecutor);
}
也就是说 * ! O P 7 g终究的request是SingleReq& 8 Guest的实例,需求留意的是Single6 b H 7 ? *Request是一个带泛型的类。这儿的R同RequestBuilder的泛型是相同的。即RequestB@ K 8 * x quilder 对应SingA j P # eleRequest。
网络恳求的建议:r% 5 ; hequsetManage. ` T R O s G i )r的track办法:
synchronized void track(@NonNull Target<?> target,o q z * m z @NonNull Request request) {
targetTracker.track(target);
requestTracker.runRequest(requestp 1 0);
}
从Glide中咱们知道每个requestManX k Y Pager都有与其绑定生命周期的activi| # } ` b 4 pty或许fragment: 然后RequestManager又将对应恳求的生命周期交给RequestTracker来进行处理。
我来来看看RequestTracker的runRequest办法:
/**
*e p ? X a | I C Starts tracking the given request.
*/
public void runRequest(@NonNull+ / 3 + 3 q n 9 $ Request request) {
requests.add(reques: : h b 8 Q Mt);
if (!isPaused) {
request.begin();
} else {
request.clear();
if (Lo} u 6g.isLoggable(T k P h h ~AG, Log.VERB0 G j + ( ) 1OSc } z 6 / L A i |E)) {
Log.v(TAG, "Paused, delaying request");
}
pend_ X + ; . ingRequesm - O s P q Zts.add(request);
}
}
能够看到在这儿假如当时状况是暂停的那X S A 7 b d # h 6么将request参加到一个0 ~ k 0 l E W f待履行的列表中,等候下次能够履行的时分进行加载,处于非暂v ; P q =停状况调用request的begin()直接进行加载。
由前面的常识咱们知道这个request是一个SingleRequest方针。咱们来看看它的begin办法:
@Override
public syncP w - { s _ 7 bhronized v5 = ( - w / Yoid begin() {
assertNotCallingCallbacks();
stateVerifier.throwIfRecycled();
startTime = LogTime.getLogTime();
if (mJ U 6 ] g Jodel == null) {
if (Util.isValidDimensions(overrideWidth, overrideHeight)) {
wid 1 Y # [th = overrideWidth;
height = overrideHeight;
}
int logLevel = ge! Z l ; 0 R L D HtFallbackDrawable() == null ? Lo- 3 5 I ,g.WARN : Log.DEBUG;
onLoadFa_ R 4iled(new GlideException(q 1 Q H n B p"ReV J ; T R 5 c Tceived null model"), logLevel);
return;
}
if (status == Status.RUNNING) {
throw new IllegalArgumentException("CannoN s % _ e lt restart a running request");
}
if (status == Status.COMPLETE) {
onResourc? 3 v e I Q V q 3eReady(resource, DataSour] r S 3 [ o } Dcf H S n $ 0e.MC L v /EMORY_CACHE);
return;
}
statl T C k + ` # Xus = Status.WAITING_x Z % , FFOR_SIZE;
if (Util.isValidDimensions(overrideWidth, overrideHeigh+ I J E Rt)) {
onSizeReady(overrideWidth, oved | ^ 6 z { 0 Y ,rrideHeight);
} else {
target.getSize(this);
}
iP 9 : u b nf ((status == Status.RUNNING || statuG I fs == Status.WAITING_FOR_SIZE)
&& canNotifyStatusChanged()) {
targ C t 7 Y p 3 `get.onLoadStarted(getPlaceholderDrawable());
}
if (IS_VERBOSE_LOGGABLE) {
logV("finished run method in " + LogTime.getElapsedMillis(startTime));
}
}
这个办G ] / { %法有点长,可是逻辑分厂简略。需求留意的有下面几点:
- 假如model为T ; L N Z i空那么直接回调加载失利,这儿的model是咱们在调用RequestManager的 load办法时传递的方针。
- 假如当时的宽高可用那么直接调用onSizeReady进行加载,不然经过targetgetSizeU X O M l(SizeReadyCallback cb)注册监听,等到target的宽高可用的时分在回调onSizeRe| 8 H A m D 5 uady。进行加载。
- 假如当时状况是运行或许等候size预备则会调用target.onLoadStarted(),这儿咱们会设置占位图进行显现。
咱们来看看onSizeReady的加载的完结:其中心就只要一句:调用engine的load办法进行{ 4 j / W加载。
咱们来看看engine的load完结:
public synchronized <R> LoadStatus load(
GlideContext glidZ f 5 . R V :eContext,
Object model,
Key signature,K w 8 {
int width,
int height,
Class<?>W T M i ?; resourceClass,
Class<R> transcodeClass,
Priority priori5 m yty,F d X P 4
DiskC$ : $ D _ . R _acheStratee o b , 1 Igy diskCacheStrategy,
Map<Cn # X Flass<?>, Transformation<?>> transformationsE } C $ ! h c,
boolean isTransformationRequired,
boolean isScaleOnlyOrNoTransform,
Options options,
boi x [ F a b =olean isMemoryCacheable,
boolean useUnlimitedSourceExecutor . ~ Y 1 3 a mPool,
boolean useAnimationPool,
boolean onlyRetrieveFromCac } he,
ResourceCallback cb,
Execu] } m / ( G D C ttor callbackExecutor) {
long startTime = VERBOSE_IS_LOGGABLE ? LogTime.getL g ` i w K f 2 OogTime()V E a J : 0;
EngineKey key = keyFactory.buildKey(. | R 1 qmodel, signature, width, height0 D F n, transformations,
resourceClass, transcodeClassi ` & D t ( i / w, options)o E { ) h ) ;;
//从活动资源中进行加载
EnginF J { heResource<?> acS N { m ative = loadFromActiveResources(key, isMemoryCacheable);
if (active != null) {
cb.onResourceReady(active, DataSource.MEMORY_CACHE);
if (VERBOSE_IS_LOGGABLS | S j / ) o RE) {
logWithTimeAndKey("Loaded resource from active resources", startTime, key);
}
return null! } 4 J c W ? u;
}
//从缓存中进行加载
EngineResource<?> cached = loadFromCache(key, isMemoryCacheable);
if (cached != null) {
cb.onResourceReady(cached, DataSource.MEMORY_CACHE);
if (VERBOSE_IS_LOGGABLE) {
logWithTimeAndKey("Loaded resource from cache", startTime7 , Z H ; 5 r v, key);
}
return null;
}
EngineJob&lB a Y - W }t{ v z;?> current = jobs.get(key, onlyRetrieveFromCache);
//假如存在异步加载的key阐明已经有相同的加载正在进行中
if (% C s o u }current != null) {L . t C z X p a ?
current.addCallback(} v Vcb, callbackExecutor);
if (VERBOSE_IS_LOGGABLE) {
logWithTimeAndKey("Added to existing load", startTime, key);
}
return new Load) T 0 6 cStatus(cb, current);
}
//^ _ M L开启线程进行异步加载
EngT h Y 0 iineJob<R&gL F j [t; engin0 c 6 feJob =
engineJobFactory.build(
key,
is/ w a ~ x 4 1 b $MemoryCacheable,
useUnlimitedSourceExecutot [ 2rPool,
useAnimationPool,
onlyRetrieveFromCache);
//留意下这个R它是] 1 3 Z 7 6 } V依据transcodeClass来进行决议的,这个值是SingleRequest<R># L F的R进行限制,从前面咱们
//知R = : 1 M g { V道SingleRequest&x v C %lt;R>同RequestB 0 A 9 ] kBuilder<Tra+ K OnscodeType>的TranscodeTypeu o X s &相同。
//即它也是一个Drawable方% ` r # y针
DecodeJob<R> decodeJob =
decodeJobFactory.build(
glideContext,
model,
key,
signature,
wy } ( k o /idth,
height,
resourceClass,
transcodeClass,
priority,
diskCacheStrategy,
transformations,
isTransfz T B 6 o GormationRequired,
isScaleOnlyOrNoTransform,
onlyRetrieveFromCache,
options,
engineJob);
jobs.put(key, engineJob);
engineJob.addCallback(cb, callbackExecutor);
engineJob.start(decodeJob);} I m d $ N
if (Vu K ] 9 t B RERBOSE_IS_LOGGABLE) {
logWithTimeG i = g FAndKey("Started new load"t ^ Y - C ?,@ ] * k startTime, key);
}
return new LoadStatus(cb, engineJob);
}
从上面的流程能够看出Glide的图片加载有三个来历:
- 活动资源
- 内存缓存
- 文件中进行加载
由上面的代码咱们能够看出,g ) 1 Z l N a 3终究engineJob.start(decodeJob)t t t U ^ e B完结图片加载,decodeJob是一个runnable方针咱们直接去看看它的run办法。它的中心代码就只要一句:调用runWrapped()。咱们来看看runWa X s & % k rapped的及其相关的完结
private void runWrapped(_ E 5 5 U 9 J %) {
//依据runReason获取状况
switch (runReason) {
case INITIALIZE:
stage = getNextStage(Stage.INITIALIZE);
currentGenerator = getNextGenerator();
runGenerators();
break;
case SWITCH_Tu 3 8 Q K n JO_SOURCE_SERVICE:
runGenerators();
break;
case DECODE_DATA:
decodeFromRetrievedData();
break;
default:
throw new IllegalStateException("Unrecognized run reason: " + runReason);
}
}q } X t R {
private Stage getNextStage(Stage cur= Y | r [ M 8 u Vrent) {
switch (current) {} x w L 3 % # y
case INITIALIZE:
return diskCacheStrategy.decodeCachedResource()
? Stage.RESOURCE_CACHE : getNextStage(Stage.RESOURCE_CACHE);
caseh N f c RESOURCE_CACHE:
return diskCacheStrategy.decodeCachedData()
? Stage.DATA_CACHE : getNextStage(Stage.DAo W z _ ?TA_CACHE);
case DATA_CACHE:
// Skip loading from source ifz D 8 b Z @ l P ] the us| L ~ H 5er opted to only retriev( u 6 K y & (e the resource from cache.
return onlyRetH W Y ! ` mrieveFromCache ? Stage.FINISHED : Stage.3 . l qSOURCE;
case SOURCE:
case FI^ = m a A b wNISHED:
return Stage.FINISHED;
default:
throw new IllegalArgumentException("Unrecognized stage: " + current);
}
}
private DataFetcherGenerator getNextGeneratorc ! _ b & x() {
switch (stage| 8 n) {
case RESOURCE_CACHE:
return new Rej 8 jsourceCacheGenerator(decodeHelper, this);
case DATA_CACHE:
return new Dati o l ! Y w M uaCacheGenerM 7 n )ator(decodeHelper, thE Y ?is);
caF + 8se SOURCE:
return new: } ^ ~ 8 { SourceGenerator(C % : b h & ?decodeHelper, this);
case FINISHED:
return null;
default:
throw new Illed S t l 1 | ugalStateException(Z n E 5 ? Q"Unrecognized stage: " + stage);
}
}
private void runGenerators() {
currentThread = ThrU # w Z _ %ead.currentThread();
sa C f [tartFetchTime = LogTime.ge] 4 | C $tLogTime();
boolean isStarteX $ o 7 h ; K Cd = false;
while (!isCancelled &w ! w & currentGenerator != null
&& !(isStarted = currentGenerator.startNext())) {
stage = getNextStage(stage);
currentGenerator = getNextGenerator();
if (stage == Stage.SOUR; R @ xCE) {
reschedule();
return;
}
}
// We've run out of stages and generators, give up.
if ((st0 Z N [age == Stage.FINISHED || isCancelled) && !isS 9 & = p _ f iStarted) {
not{ | b w 0 yifyFailed();
}
// Otherwise a generator started a new loa~ d I `d and we expect to be called back in
// onDataFetcherReady.
}
上面的代码逻辑比较复杂,这儿不做具体的阐明~ q 3 H Q ) O ,( 4 v E Y w a r可是它的大约意思就是,在runGenerators办法中经过调用D@ ? z G R {ataFetcherGeneratZ P ? T R / & kor的startNext()办法先从文件中读取图片资源(别离是资源类型和数据来历),假如不存在咱们在7 v l . 4从网络进行加载。再依2 | ` o l !据官方文档的介绍glx F %ide的缓存分为4级
- 活动资源 (Active Resources) – 现在是否有另一个 View 正在展现m h : + u这张图片?
- 内存缓存 (Memory cachP 0 P j . e be) – 该图片是否最近被加载过并仍存在于内存中?U & m B 5 + , c
- 资源类型(6 U !Resource) – 该图片是否之前曾被解码、转换并写入过磁盘缓存?对应ResourceCacheGenerator
- 数据来5 p 5 b $ =历 (Data) – 构建这个图片的资源是否之前曾被写入过文件缓存?对应DataCacheGenerator
由前面的G a } m d流程剖析咱们知道1、2级缓存在Engine类的load中调用,3、4级缓存在DecodeJob中进行调用。这儿/ = H咱们不对缓存的调用进行剖析。直接进入网络在在的剖析。
在runGenerators()办法中当stage == Stage.SOURCE会退出循环而且# I f & d 2 T l ~调用rescheduleN E F O [ k Z [()履行DecodeJob的run办8 t { G v [ ] ~法
@Override
public void rescx 3 `hedule() {
runReason = RunReason.SWITCH_TO_SOURCE_SERVICE;
callba! e z Z r ) 1ck.res9 % rchedule(thiL e $ Ss);
}
由前面的常识咱们知道这个时分会在runGenerators办法中履行SourceGenerator的startNext()办法。其完结如下
public boolean startNext() {
if (dataToCache != null) {
Object data = dataToCaH | U $ 4 V k vche;
dataToC* I ( Vache = null;
cacheData(data);
}
if (sourceCacheGenerator != null && sourceCacheGenerv y V N Z O Gator.startN# p W o w b p Dext()) {
return true;
}
sourceCg # zacheGenerator = null;
loadData = null;
boolean started = faC h Llse;
while (!started && hasNextC ( b 1 v 4 X 8 LModelLoader()) {
loadData = helper.getLoadData().get(loadDataListIndex++);
if (loadData !=} x { ~ w Q null
&& (helper.getDiskCacheStrategy().isDataCacheable(loadData.fetcher.getDataSource())
|| helper.hasLoadPath(loadData.fetcher.getDataE k L _ ) Class()))) {
started = true;
loadData.fetcheru y H Q g E x 8.loadData(helper.getPriority(), this);
}
}
return started;
}
经过debug咱们发现loadData的fetcher方针在modelE X h H ! W 2是图片网络地址时是MultiModelLoader的内部类。
在传入图片网络地址的情况下终究调用的Hv D b b * e q 5ttpUrlFetcher进行图片加载。当数据预备完结后回调到SourceGen1 Y o R |erator的onDataRead[ ( f # 3 c / M 3y办法,假如不需求进行缓存则直接告诉数据预备完结,不然先进行缓存在告诉数据预备| % / K M c完结。
@O. . V } &verr= ] ) 9 ; . a & `ide
public void onDataReady(Object data) {
DiskCacheStrategy diskCax A ocheStrategy = helperw c ; ; J h.getDiskCacht k H a 2eStrategy();
if (datar 7 % b V m X _ != null && diskCacR x F c Y ~ ?heStrategy.isDataCacheable(loadData.fetcher.getDataSource())) {
dataToCache = data;
// We might be being calY O u ` r Q D eled back on someone else's thrW U Q B {ead. Before doing anything, we shM P I z mould
// reschedule to get back onto Glide's thread.@ c ? H . p Z ]
cb.e A G A treschedule();
} else {
cb.onDataFetcherReady) Y f(loadData.sourceKey, data, loadData.R & f ifetcher,
loadData.fetcher.getDataSource(), originalKey);
}
}
终究它们都会调用DecodeJob的onDataFetcherReady()这个办法又会调用decodeFromRetrievedData()而
decodeFromRetrievedData当资源预备好的时分会调用notifyEncodeAndRelease()来告诉数据预备完结。
@Override
public void onDataFetcherReady(Key sourceKR ( Be* L D } { V ` M Oy, Object data, DataFetcher<?> fetcher,
DataSource dl d l 8 ! $ 8ataSource, Key attemptedKey) {
this.currentSouf 7 i ~rceKey = sourceKey;
this.currentData = data;
this.^ = s WcurrentFetcher = fetcher;
this.curK z F I wrentDataSource = dataSource;
this.currentAR ~ ? % }ttemptingKey = attemptedKey;
if (Thread.curreno z V n 1 YtThread() !0 P 1 Z . Q I E= currentThread) {
run7 H : F A jReason = RunReason.DECOT S [ r uDE_DATA;
callback.reschedulez u T P T 8(this);
} else {
GlideTrace.beginSection("DecodeJob.decodeFromRetrievedData");
try {
decodeFromRetrievedData();
} finally {
GliG E P D H ` GdeTrace.endSection();
}
}
}
private void notifyEc 2 c b gncodeAndRelease(Resource<R> resource, DataSource dataSource) {
if (resog E 9 S $ Purce ins, w }tanceof In] i ^ = I uitiQ k t b ^ Falizable) {
((Initializable) resoL E u } O $urc% ~ pe).initialize();
}
Resource<RJ w z 9 @> result = resource;
Lo1 U U w ` hckedResource<R> lockedResource = null;
if (deferredEncodeManager.hasResourceToEncode()) {
lockedResourm a x oce = LockedResource.obtain(resource);
result = lockedResource;
}
notifyComplete(result, dataSource);
stage = SK ] _ ` 1 * }tagea L {.ENCODE;
try {
if (deferredED A 9 : h x w | 3ncod& H ; J ^eManager.hasResourceToEncode()) {
deferredEncodeManj w 0ager.encode(diskCachf 7 - W ceProvider, options);
}
} finally {
if (lockedResource != null) {
lockedResource.unlock();
}
}
//0 g - 8 N + Call onEncodeComplete outside the finally block so thatI 7 r N F M - N 3 it's not called if the encode procT s 9 V 8 3ess
// throws.
onEncodeComplete();
}
private void notifyCompleX V Y = hteO 4 L & 6 F I + w(Resource<R&: [ : Rgt; resource, DataSource dataSource) {
setNotifiedOrThrow();
callb^ 5 tack.onResourceReady(resouK d Y = , Erce, dataSourcA y J _ g J ve);
}
咱们需求留意notifyComplete办法里这个c$ V l ? Vallback是创立DecodeJob方针传入的EngineJob,因而调用的是Engiq x lneJob的onResourceReady()。咱们看看他的onResok & J R B B 6urceReady办法完结
@Override
public void onResourceReady(Resource<R> resource, DataSource dataSource) {
synchronized (this) {
this.resource = resource;
this.dataSource = dataSource;
}
notifyCallbacksOfResult();
}
@; ( + MSynthetic
void notifyCI o 0 vallbacksOfResult() {
ResourceCallbacksAndExecutors copy;
Key localKeT W W 8 [y;
EngineResource<?> localRh O Z 4 c g ( & Gesource;
synchronized (this)K x t t w - ? ] $ {
stateVerifier.throwIfRe : P j $ @ V 4ecycled();
if (is5 : _ k l N 1 1CancelK 5 j oled) {
// TODO: Seems like we might as well put this in the m, @ H 4 ) 9 &emory cache instead of just recycling
// it since we'& a ^ve gottent - W ? N / * { J this far...
resource.recycle();
re& ) (lease();
return;
} else if (cbs.isEmpty()) {
throw nes ) Ew IllegalStateException("Received a resoP J 2 M x h Z xurce without any cal@ L nlbacks to notify");
} else if (hasResource) {
throw new IllegalStau + 4 . T O ` MteException("Already have resource");
}
engineResource = engineResourceFactory.build(resource, isCV ( M 2 ( z ! jacheable);
// Hold on to resource fos D . ^ U 4r duration of our callbacks below so we don't recycle it in the
// m9 q [ U o m J Aiddle of notifying if it synchronousl# l t j Hy released by one of the callbacks. Acquire it under
// a lock here so that any newly added callback that executes before the next locked section
// belI = V 7 ] ) ; aow can't recycle the resource before we calh q N b 3 E 2 h {l the callbacks.
hasResource = true;
copy = cbs.copy();
incrementPendingCallbacks(copy.size() + 1);
localKey = key;
localResource = engineResource;
}
//这儿会将图k C Q ; R片信息参加活动资源,
listener.onEngineJobComplete(this, localKey, localResource);
//for循环终究履行SingleRequest的onResou2 P 8 X L * WrceReady办法
for (final ResourceCallbackAndExecutor entry : copy) {
entry.executor.execute(new CallR7 W Q J { VesourceReady(entry.cb));
}
decrementPendingCallbacks();
}
在忽略其他条件的情况下Sq g n y YingleRequest的onResoue Y 2 Y M trceReady()终究会履行一句代码:
target.onResource) e . @ KReady(result, animation);
咱们假定图片加载G 2 X的时分into传入的是一个ImageView) i ] 0 Y z。前面的时分没有剖析这个target是怎么进行构建的这儿咱们补充阐明一下:
public ViewTarget<I. ~ N KmageView, TranscodeType> into(@NonNx 2 ) % 7ull ImaQ l U g tgeView view) {
///省略其它代码
retJ 0 G - ? vurn into(
/** 构建targ$ 2 s L o C 6et方针 */
glideContext.buildImageViewTarget(viewq j N ^ #, transcodeClass),
/*tl H .argetListener=*/ null,
requestOptions,
Executors.mainThreadExecutor());
}
target方针经过glideContext.buildImageViewTarget(vi; V [ # – Vew, transcodeClass)来进行构建:咱们看看GlideContext对应的完结:
@NonNull
public <X> ViewTarget<ImageView, X> buildImageViewA L } pTarget(
@NonNull Ima= i ] 3 i * m `geView imageView, @NonNull Class<X> transcodeClass) {
return imageViewTargetFactory.buildTarget(imageView, transcodeClass);
}
public class ImageViewTargetFactory {
@NonNull
@SuppressWarnings("unchecked")
public <Z> ViewT? 2 *arget<ImageView, Z2 H&g` U 2 7 7t; buildTarget(@Np u ] F 8 H Q 0 .onN_ ~ n Z 9 { S }ull ImagM ) ? J - 7 P + 6eView view,
@NonNull Class<Z> clazz) {
if (Bitmap.class.equals(clazz)) {
return (ViewTarget<c 0 g 5 E z f 3 -ImageView, Z>) new BitmapImageViewTarget(view);
} else if (Drawable.class.isAssignableFh ! J 9 arom(clazz)) {
return (ViewTarget&P H ! 6 X & ! mlt;ImageView, Z>) new DrawableImageViewTarget(view)O y;
}; F Z 0 W p @ o 2 else {
throw new IllegalArgumentException(
"Unhandled class:M . 0 Z V " + clazz + "D l i W c h 7,G q 4 / tq H !ry .as*(Class).transcode(ResourP _ U a 8 } xceTranscoder)")` O - Z ^ A G (;
}
}
}
由上面s 0 m 9 ~的代码咱们知道假如RequestBuilder的transcodeClass是Bitmap那么target就是Bh s G w ^ UitmapImageViewTarg q # V c g Q xet,假如是Drawable的子类那么target就是Drad ` m twableImageViewTarget。
咱们挑选DrawableIma= C = F C P z & ZgeVi8 C = ? F ,ewTarget进行检查:因为DrawableImageViewTargT * # [et没, . Q U = ; Z @有onResourceReady办法咱们在它的父类ImageViewTarget中进行检查
@Override
public void onResourc @ % ?ceR( 6 ! R * = 0 pen 7 C ? a X = = Aady(@NonNull Z resource, @Nullabt 9 * K wle Transition<? super Z> trans; A 3 B q ^ 8ition) {
if (transition == null || !transitip p = ~on.transition(resource, this)) {
setResourceInternal(resource);
} else {
maybeUpdateAnimatabG 6 8 V s _le(resource);
}
}
DrawableImageViewTargety M s /的完结:能够h d U l Q [ v .看到它的setResource办法给ImageView设置了加载图片
public: ? j N q ( class DrawableImageViewTarget extends ImageViewTarget<Drawable> {
pu/ d 9 7blic Drawableq ? ) L 0 a 6 r hImageViewTarget(ImageView view) {
super(view);
}
/**
* @deprecated Use {@link #waitForLayout()} instead.
*/
// Public API.
@SuppressWarnings({"unused", "deprecation"})
@Deprecated
publicz 8 ? Dq 1 | j / FrawableImageViewTarget(ImageView view, boolean waitForLayout) {
super(view, waitFop ^ # A I p # TrLayout);
}
@Override
protected void setResource(@Nullable Drawable resource) {
view.setImageDrawable(resourh / ^ E 2 P w w yce);~ D / * F + l j
}
}
小结:
到这儿glide的图片% j T b / $ 7 M加载流程就剖析完了。因N ^ ^ M为T 8 K篇幅较长咱们对glide的加载流) V _程进行一个简略的回顾。
Glide加载时序图: