Glide Engine


圖片加載引擎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师逸。

引擎load()流程圖

二司倚、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)

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市揍愁,隨后出現(xiàn)的幾起案子呐萨,更是在濱河造成了極大的恐慌,老刑警劉巖莽囤,帶你破解...
    沈念sama閱讀 221,820評(píng)論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件谬擦,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡朽缎,警方通過(guò)查閱死者的電腦和手機(jī)惨远,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,648評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)话肖,“玉大人北秽,你說(shuō)我怎么就攤上這事±俏” “怎么了羡儿?”我有些...
    開(kāi)封第一講書人閱讀 168,324評(píng)論 0 360
  • 文/不壞的土叔 我叫張陵礼患,是天一觀的道長(zhǎng)是钥。 經(jīng)常有香客問(wèn)我掠归,道長(zhǎng),這世上最難降的妖魔是什么悄泥? 我笑而不...
    開(kāi)封第一講書人閱讀 59,714評(píng)論 1 297
  • 正文 為了忘掉前任虏冻,我火速辦了婚禮,結(jié)果婚禮上弹囚,老公的妹妹穿的比我還像新娘厨相。我一直安慰自己,他們只是感情好鸥鹉,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,724評(píng)論 6 397
  • 文/花漫 我一把揭開(kāi)白布蛮穿。 她就那樣靜靜地躺著,像睡著了一般毁渗。 火紅的嫁衣襯著肌膚如雪践磅。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書人閱讀 52,328評(píng)論 1 310
  • 那天灸异,我揣著相機(jī)與錄音府适,去河邊找鬼。 笑死肺樟,一個(gè)胖子當(dāng)著我的面吹牛檐春,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播么伯,決...
    沈念sama閱讀 40,897評(píng)論 3 421
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼疟暖,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了蹦狂?” 一聲冷哼從身側(cè)響起誓篱,我...
    開(kāi)封第一講書人閱讀 39,804評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎凯楔,沒(méi)想到半個(gè)月后窜骄,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,345評(píng)論 1 318
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡摆屯,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,431評(píng)論 3 340
  • 正文 我和宋清朗相戀三年邻遏,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片虐骑。...
    茶點(diǎn)故事閱讀 40,561評(píng)論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡准验,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出廷没,到底是詐尸還是另有隱情糊饱,我是刑警寧澤,帶...
    沈念sama閱讀 36,238評(píng)論 5 350
  • 正文 年R本政府宣布颠黎,位于F島的核電站另锋,受9級(jí)特大地震影響滞项,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜夭坪,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,928評(píng)論 3 334
  • 文/蒙蒙 一文判、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧室梅,春花似錦戏仓、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書人閱讀 32,417評(píng)論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至间涵,卻和暖如春嗓奢,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背浑厚。 一陣腳步聲響...
    開(kāi)封第一講書人閱讀 33,528評(píng)論 1 272
  • 我被黑心中介騙來(lái)泰國(guó)打工股耽, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人钳幅。 一個(gè)月前我還...
    沈念sama閱讀 48,983評(píng)論 3 376
  • 正文 我出身青樓物蝙,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親敢艰。 傳聞我的和親對(duì)象是個(gè)殘疾皇子诬乞,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,573評(píng)論 2 359