圖片加載引擎Engine工作流程
一碗暗、Engine 引擎
所有圖片加載渠道公用,管理Jobs昌阿,load()方法饥脑,EngineJob,DecodeJob工廠創(chuàng)建懦冰。
public <R> LoadStatus load(
GlideContext glideContext,
Object model,
Key signature,
int width,
int height,
...
ResourceCallback cb) {
long startTime = LogTime.getLogTime();
EngineKey key = keyFactory.buildKey(model, signature, width, height, transformations,
resourceClass, transcodeClass, options);
EngineResource<?> active = loadFromActiveResources(key, isMemoryCacheable);
if (active != null) {
cb.onResourceReady(active, DataSource.MEMORY_CACHE);
return null;
}
EngineResource<?> cached = loadFromCache(key, isMemoryCacheable);
if (cached != null) {
cb.onResourceReady(cached, DataSource.MEMORY_CACHE);
return null;
}
//開(kāi)始從磁盤或網(wǎng)絡(luò)獲取
EngineJob<?> current = jobs.get(key, onlyRetrieveFromCache);
if (current != null) {
current.addCallback(cb);
return new LoadStatus(cb, current);
}
EngineJob<R> engineJob =
engineJobFactory.build(
key,
isMemoryCacheable,
useUnlimitedSourceExecutorPool,
useAnimationPool,
onlyRetrieveFromCache);
DecodeJob<R> decodeJob =
decodeJobFactory.build(
glideContext,
model,
key,
...
options,
engineJob);
jobs.put(key, engineJob);
engineJob.addCallback(cb);
engineJob.start(decodeJob);
return new LoadStatus(cb, engineJob);
}
1灶轰,內(nèi)存查找
創(chuàng)建EngineKey,若支持內(nèi)存緩存刷钢,首先笋颤,loadFromActiveResources方法,根據(jù)key在ActiveResources類中獲取資源EngineResource内地。如果不是空伴澄,回調(diào),表示從內(nèi)存獲取阱缓,否則繼續(xù)非凌。其次,loadFromCache方法荆针,根據(jù)key從MemoryCache中獲取清焕,同樣支持內(nèi)存緩存并蝗。
返回的Resource<?>類型,可能是EngineResource秸妥,不是則包裝一下滚停。將cache返回并加入ActiveResources。如果cache不空粥惧,依然回調(diào)键畴,否則繼續(xù)。
以上這兩種情況都是從內(nèi)存獲取數(shù)據(jù)突雪,onResourceReady回調(diào)方法表明來(lái)源是MEMORY_CACHE起惕。
如果在內(nèi)存緩存中未找到,需要從磁盤緩存或網(wǎng)絡(luò)中獲取咏删。
2惹想,ResourceCallback回調(diào),SingleRequest實(shí)現(xiàn)接口督函,EngineResource類型嘀粱,來(lái)源如MEMORY_CACHE。
3辰狡,每個(gè)圖片請(qǐng)求建立一個(gè)引擎任務(wù)EngineJob锋叨。承接具體load工作,管理記錄Jobs宛篇。實(shí)現(xiàn)DecodeJob.Callback接口娃磺。EngineJob保存cb,開(kāi)始任務(wù)叫倍。
根據(jù)key在Jobs類偷卧,獲取EngineJob,存在時(shí)吆倦,直接LoadStatus返回听诸。
EngineJobFactory和DecodeJobFactory工廠分別創(chuàng)建兩個(gè)Job,EngineJob和DecodeJob逼庞。將EngineJob根據(jù)key存儲(chǔ)在Jobs類。
4瞻赶,DecodeJob任務(wù)赛糟,當(dāng)任務(wù)complete,通知DecodeJob.Callback砸逊,回調(diào)方法璧南,onResourceReady()。
進(jìn)一步路由到主線程通知到EngineJob的cb即ResourceCallback师逸。
二司倚、EngineJob
實(shí)現(xiàn)DecodeJob.Callback接口,交給DecodeJob,任務(wù)complete后通知动知。
EngineJob的start()方法皿伺,啟動(dòng)任務(wù)。
GlideExecutor線程池盒粮,管理線程任務(wù)鸵鸥。
DecodeJob是Runnable任務(wù),該任務(wù)可以從資源中丹皱,文件緩存妒穴,或者網(wǎng)絡(luò)中獲取圖片。選擇一個(gè)合適的線程池摊崭。
public void start(DecodeJob<R> decodeJob) {
this.decodeJob = decodeJob;
GlideExecutor executor = decodeJob.willDecodeFromCache()
? diskCacheExecutor
: getActiveSourceExecutor();
executor.execute(decodeJob);
}
willDecodeFromCache()方法讼油,判斷從Disk或Resource緩存中獲取,選擇合適的線程池執(zhí)行任務(wù)呢簸。將DecodeJob任務(wù)派發(fā)給它矮台。
內(nèi)部有四個(gè)GlideExecutor線程池,均在GlideBuilder中配置阔墩。
boolean willDecodeFromCache() {
Stage firstStage = getNextStage(Stage.INITIALIZE);
return firstStage == Stage.RESOURCE_CACHE || firstStage == Stage.DATA_CACHE;
}
在INITIALIZE狀態(tài)下嘿架,下一個(gè)Stage將根據(jù)DiskCacheStrategy策略類決定,該類默認(rèn)的decodeCachedResource方法啸箫,允許從資源獲取圖片耸彪,Stage設(shè)置RESOURCE_CACHE,如果不允許忘苛,再判斷decodeCachedData方法蝉娜,從Disk緩存獲取圖片,Stage設(shè)置DATA_CACHE扎唾,兩者都不允許時(shí)召川,再次執(zhí)行g(shù)etNextStage方法,存在onlyRetrieveFromCache標(biāo)志胸遇,說(shuō)明只能從緩存荧呐,而緩存又不存在,只能結(jié)束纸镊。否則倍阐,Stage設(shè)置SOURCE。
當(dāng)Stage是RESOURCE_CACHE或DATA_CACHE時(shí)逗威,從依然是從緩存獲取峰搪。選擇的線程池是diskCacheExecutor,如果Stage是Source狀態(tài)凯旭,選擇線程池sourceExecutor概耻。還有animationExecutor和sourceUnlimitedExecutor使套。針對(duì)不同的數(shù)據(jù)源,線程池不同鞠柄,影響的是每種數(shù)據(jù)源線程復(fù)用的策略侦高。
三、線程耗時(shí)任務(wù)
線程運(yùn)行DecodeJob任務(wù)春锋,實(shí)現(xiàn)Runnable接口矫膨,在非內(nèi)存獲取圖片資源時(shí),將該任務(wù)分配給適當(dāng)?shù)木€程池期奔,從資源侧馅,Disk緩存,或網(wǎng)絡(luò)中獲取呐萌。
public void run() {
TraceCompat.beginSection("DecodeJob#run");
DataFetcher<?> localFetcher = currentFetcher;
try {
if (isCancelled) {
notifyFailed();
return;
}
runWrapped();
} catch (Throwable t) {
if (stage != Stage.ENCODE) {
throwables.add(t);
notifyFailed();
}
if (!isCancelled) {
throw t;
}
} finally {
if (localFetcher != null) {
localFetcher.cleanup();
}
TraceCompat.endSection();
}
}
最終在DecodeJob的notifyComplete方法馁痴,通過(guò)DecodeJob.Callback回調(diào)將數(shù)據(jù)回復(fù)到請(qǐng)求EngineJob中,數(shù)據(jù)包裝Resource<>類型肺孤。
private void notifyComplete(Resource<R> resource, DataSource dataSource) {
setNotifiedOrThrow();
callback.onResourceReady(resource, dataSource);
}
將資源Resource和數(shù)據(jù)來(lái)源DataSource存儲(chǔ)在EngineJob罗晕,發(fā)送消息到主線程處理,轉(zhuǎn)換資源EngineResource子類赠堵。
最后ResourceCallback回調(diào)小渊,通知外部load方法傳入的cb對(duì)象。即SingleRequest實(shí)現(xiàn)的ResourceCallback接口茫叭。
資源通知SingleRequest內(nèi)部Target酬屉。
任重而道遠(yuǎn)