glide緩存

分為內(nèi)存緩存以及硬盤緩存孤里,內(nèi)存緩存又分為lruresourchcache和弱引用緩存燕酷。
緩存的key粮揉,參數(shù)很多膊畴,通過(guò)equals和hashcode算法來(lái)判斷是否是同一個(gè)key.

先是從loadFromCache里面讀取织中,內(nèi)部代碼先是從cache里面移除锥涕,添加到弱引用的資源里面。LinkedHashMap, LruCache 實(shí)現(xiàn)了MemoryCache抠璃。如果cache里面沒(méi)有這條數(shù)據(jù)站楚,從loadFromActiveResources里面讀取。還是沒(méi)有數(shù)據(jù)搏嗡,從網(wǎng)絡(luò)獲取窿春。
對(duì)于內(nèi)存緩存,正在使用的圖片使用弱引用緩存采盒,不在使用的圖片使用lrucache來(lái)進(jìn)行緩存旧乞。
為啥使用弱引用緩存:防止lrucache將正在使用的圖片緩存清除掉。

public <T, Z, R> LoadStatus load(Key signature, int width, int height, DataFetcher<T> fetcher,
            DataLoadProvider<T, Z> loadProvider, Transformation<Z> transformation, ResourceTranscoder<Z, R> transcoder,
            Priority priority, boolean isMemoryCacheable, DiskCacheStrategy diskCacheStrategy, ResourceCallback cb) {
        Util.assertMainThread();
        long startTime = LogTime.getLogTime();

        final String id = fetcher.getId();
        //生成key
        EngineKey key = keyFactory.buildKey(id, signature, width, height, loadProvider.getCacheDecoder(),
                loadProvider.getSourceDecoder(), transformation, loadProvider.getEncoder(),
                transcoder, loadProvider.getSourceEncoder());

        //內(nèi)存緩存讀取保存的數(shù)據(jù)
        EngineResource<?> cached = loadFromCache(key, isMemoryCacheable);
        if (cached != null) {
            cb.onResourceReady(cached);
            if (Log.isLoggable(TAG, Log.VERBOSE)) {
                logWithTimeAndKey("Loaded resource from cache", startTime, key);
            }
            return null;
        }
        //內(nèi)存的弱引用當(dāng)中讀取數(shù)據(jù)
        EngineResource<?> active = loadFromActiveResources(key, isMemoryCacheable);
        if (active != null) {
            cb.onResourceReady(active);
            if (Log.isLoggable(TAG, Log.VERBOSE)) {
                logWithTimeAndKey("Loaded resource from active resources", startTime, key);
            }
            return null;
        }

        EngineJob current = jobs.get(key);
        if (current != null) {
            current.addCallback(cb);
            if (Log.isLoggable(TAG, Log.VERBOSE)) {
                logWithTimeAndKey("Added to existing load", startTime, key);
            }
            return new LoadStatus(cb, current);
        }
        //網(wǎng)絡(luò)獲取數(shù)據(jù)
        EngineJob engineJob = engineJobFactory.build(key, isMemoryCacheable);
        DecodeJob<T, Z, R> decodeJob = new DecodeJob<T, Z, R>(key, width, height, fetcher, loadProvider, transformation,
                transcoder, diskCacheProvider, diskCacheStrategy, priority);
        EngineRunnable runnable = new EngineRunnable(engineJob, decodeJob, priority);
        jobs.put(key, engineJob);
        engineJob.addCallback(cb);
        engineJob.start(runnable);

        if (Log.isLoggable(TAG, Log.VERBOSE)) {
            logWithTimeAndKey("Started new load", startTime, key);
        }
        return new LoadStatus(cb, engineJob);
    }

//從緩存讀取數(shù)據(jù)
private EngineResource<?> loadFromCache(Key key, boolean isMemoryCacheable) {
        if (!isMemoryCacheable) {
            return null;
        }
        EngineResource<?> cached = getEngineResourceFromCache(key);
        if (cached != null) {
            cached.acquire();
            //添加數(shù)據(jù)到弱引用當(dāng)中
            activeResources.put(key, new ResourceWeakReference(key, cached, getReferenceQueue()));
        }
        return cached;
    }

    @SuppressWarnings("unchecked")
    private EngineResource<?> getEngineResourceFromCache(Key key) {
        Resource<?> cached = cache.remove(key);

        final EngineResource result;
        if (cached == null) {
            result = null;
        } else if (cached instanceof EngineResource) {
            // Save an object allocation if we've cached an EngineResource (the typical case).
            result = (EngineResource) cached;
        } else {
            result = new EngineResource(cached, true /*isCacheable*/);
        }
        return result;
    }

handleResulteOnMainThread()方法中磅氨,數(shù)據(jù)寫入內(nèi)存尺栖,先是寫入到弱引用緩存當(dāng)中,
數(shù)據(jù)寫入內(nèi)存:根據(jù)一個(gè)int數(shù)據(jù)烦租,作為這張圖片當(dāng)前被使用的次數(shù)延赌,當(dāng)這個(gè)計(jì)數(shù)器>0的時(shí)候,是在弱引用里面叉橱,當(dāng)這個(gè)計(jì)數(shù)器==0的時(shí)候挫以,調(diào)用一個(gè)回調(diào),將數(shù)據(jù)從弱引用移除掉窃祝,添加到lrucache里面掐松。通過(guò)這個(gè)計(jì)數(shù)器來(lái)判斷是寫入lrusource里面還是弱引用里面。

@SuppressWarnings("unchecked")
    @Override
    public void onEngineJobComplete(Key key, EngineResource<?> resource) {
        Util.assertMainThread();
        // A null resource indicates that the load failed, usually due to an exception.
        if (resource != null) {
            resource.setResourceListener(key, this);

            if (resource.isCacheable()) {
                activeResources.put(key, new ResourceWeakReference(key, resource, getReferenceQueue()));
            }
        }
        // TODO: should this check that the engine job is still current?
        jobs.remove(key);
    }

@Override
    public void onResourceReleased(Key cacheKey, EngineResource resource) {
        Util.assertMainThread();
        activeResources.remove(cacheKey);
        if (resource.isCacheable()) {
            cache.put(cacheKey, resource);
        } else {
            resourceRecycler.recycle(resource);
        }
    }

網(wǎng)絡(luò)獲取的時(shí)候,先是從硬盤讀取數(shù)據(jù)大磺,硬盤里面先是從result里面讀取抡句,如果沒(méi)有,再?gòu)膕ource里面讀雀芾ⅰ待榔!

class EngineRunnable implements Runnable, Prioritized {
    private static final String TAG = "EngineRunnable";

    private final Priority priority;
    private final EngineRunnableManager manager;
    private final DecodeJob<?, ?, ?> decodeJob;

    private Stage stage;

    private volatile boolean isCancelled;

    public EngineRunnable(EngineRunnableManager manager, DecodeJob<?, ?, ?> decodeJob, Priority priority) {
        this.manager = manager;
        this.decodeJob = decodeJob;
        this.stage = Stage.CACHE;
        this.priority = priority;
    }

    public void cancel() {
        isCancelled = true;
        decodeJob.cancel();
    }

    @Override
    public void run() {
        if (isCancelled) {
            return;
        }

        Exception exception = null;
        Resource<?> resource = null;
        try {
            resource = decode();
        } catch (Exception e) {
            if (Log.isLoggable(TAG, Log.VERBOSE)) {
                Log.v(TAG, "Exception decoding", e);
            }
            exception = e;
        }

        if (isCancelled) {
            if (resource != null) {
                resource.recycle();
            }
            return;
        }

        if (resource == null) {
            onLoadFailed(exception);
        } else {
            onLoadComplete(resource);
        }
    }

    private boolean isDecodingFromCache() {
        return stage == Stage.CACHE;
    }

    private void onLoadComplete(Resource resource) {
        manager.onResourceReady(resource);
    }

    private void onLoadFailed(Exception e) {
        if (isDecodingFromCache()) {
            stage = Stage.SOURCE;
            manager.submitForSource(this);
        } else {
            manager.onException(e);
        }
    }

    private Resource<?> decode() throws Exception {
        if (isDecodingFromCache()) {
            return decodeFromCache();
        } else {
            return decodeFromSource();
        }
    }

    //硬盤讀取數(shù)據(jù)
    private Resource<?> decodeFromCache() throws Exception {
        Resource<?> result = null;
        try {
            result = decodeJob.decodeResultFromCache();
        } catch (Exception e) {
            if (Log.isLoggable(TAG, Log.DEBUG)) {
                Log.d(TAG, "Exception decoding result from cache: " + e);
            }
        }

        if (result == null) {
            result = decodeJob.decodeSourceFromCache();
        }
        return result;
    }
    
   //網(wǎng)絡(luò)讀取數(shù)據(jù)
    private Resource<?> decodeFromSource() throws Exception {
        return decodeJob.decodeFromSource();
    }

    @Override
    public int getPriority() {
        return priority.ordinal();
    }

    private enum Stage {
        /** Attempting to decode resource from cache. */
        CACHE,
        /** Attempting to decode resource from source data. */
        SOURCE
    }

    interface EngineRunnableManager extends ResourceCallback {
        void submitForSource(EngineRunnable runnable);
    }
}

硬盤讀取數(shù)據(jù),會(huì)分為DiskCacheStrategy.SOURCE和DiskCacheStrategy.RESULT兩種殴蹄。在DecodeJob類當(dāng)中究抓。

public Resource<Z> decodeResultFromCache() throws Exception {
        if (!diskCacheStrategy.cacheResult()) {
            return null;
        }

        long startTime = LogTime.getLogTime();
        Resource<T> transformed = loadFromCache(resultKey);
        if (Log.isLoggable(TAG, Log.VERBOSE)) {
            logWithTimeAndKey("Decoded transformed from cache", startTime);
        }
        startTime = LogTime.getLogTime();
        Resource<Z> result = transcode(transformed);
        if (Log.isLoggable(TAG, Log.VERBOSE)) {
            logWithTimeAndKey("Transcoded transformed from cache", startTime);
        }
        return result;
    }


public Resource<Z> decodeSourceFromCache() throws Exception {
        if (!diskCacheStrategy.cacheSource()) {
            return null;
        }

        long startTime = LogTime.getLogTime();
        Resource<T> decoded = loadFromCache(resultKey.getOriginalKey());
        if (Log.isLoggable(TAG, Log.VERBOSE)) {
            logWithTimeAndKey("Decoded source from cache", startTime);
        }
        return transformEncodeAndTranscode(decoded);
    }

private Resource<T> loadFromCache(Key key) throws IOException {
        File cacheFile = diskCacheProvider.getDiskCache().get(key);
        if (cacheFile == null) {
            return null;
        }

        Resource<T> result = null;
        try {
            result = loadProvider.getCacheDecoder().decode(cacheFile, width, height);
        } finally {
            if (result == null) {
                diskCacheProvider.getDiskCache().delete(key);
            }
        }
        return result;
    }

禁止Glide對(duì)圖片進(jìn)行硬盤緩存
Glide.with(this).load(url).diskCacheStrategy(DiskCacheStrategy.NONE).into(imageView);
硬盤的寫入:

private Resource<T> cacheAndDecodeSourceData(A data) throws IOException {
    long startTime = LogTime.getLogTime();
    SourceWriter<A> writer = new SourceWriter<A>(loadProvider.getSourceEncoder(), data);
    diskCacheProvider.getDiskCache().put(resultKey.getOriginalKey(), writer);
    startTime = LogTime.getLogTime();
    Resource<T> result = loadFromCache(resultKey.getOriginalKey());
    return result;
}
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市袭灯,隨后出現(xiàn)的幾起案子刺下,更是在濱河造成了極大的恐慌,老刑警劉巖稽荧,帶你破解...
    沈念sama閱讀 211,265評(píng)論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件橘茉,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡姨丈,警方通過(guò)查閱死者的電腦和手機(jī)畅卓,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,078評(píng)論 2 385
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)蟋恬,“玉大人翁潘,你說(shuō)我怎么就攤上這事〖哒” “怎么了拜马?”我有些...
    開(kāi)封第一講書人閱讀 156,852評(píng)論 0 347
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)沐绒。 經(jīng)常有香客問(wèn)我俩莽,道長(zhǎng),這世上最難降的妖魔是什么乔遮? 我笑而不...
    開(kāi)封第一講書人閱讀 56,408評(píng)論 1 283
  • 正文 為了忘掉前任扮超,我火速辦了婚禮,結(jié)果婚禮上蹋肮,老公的妹妹穿的比我還像新娘出刷。我一直安慰自己,他們只是感情好坯辩,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,445評(píng)論 5 384
  • 文/花漫 我一把揭開(kāi)白布馁龟。 她就那樣靜靜地躺著,像睡著了一般濒翻。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書人閱讀 49,772評(píng)論 1 290
  • 那天有送,我揣著相機(jī)與錄音淌喻,去河邊找鬼。 笑死雀摘,一個(gè)胖子當(dāng)著我的面吹牛裸删,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播阵赠,決...
    沈念sama閱讀 38,921評(píng)論 3 406
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼涯塔,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了清蚀?” 一聲冷哼從身側(cè)響起匕荸,我...
    開(kāi)封第一講書人閱讀 37,688評(píng)論 0 266
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎枷邪,沒(méi)想到半個(gè)月后榛搔,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,130評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡东揣,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,467評(píng)論 2 325
  • 正文 我和宋清朗相戀三年践惑,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片嘶卧。...
    茶點(diǎn)故事閱讀 38,617評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡尔觉,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出芥吟,到底是詐尸還是另有隱情侦铜,我是刑警寧澤,帶...
    沈念sama閱讀 34,276評(píng)論 4 329
  • 正文 年R本政府宣布运沦,位于F島的核電站泵额,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏携添。R本人自食惡果不足惜嫁盲,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,882評(píng)論 3 312
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望烈掠。 院中可真熱鬧羞秤,春花似錦、人聲如沸左敌。這莊子的主人今日做“春日...
    開(kāi)封第一講書人閱讀 30,740評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)矫限。三九已至哺哼,卻和暖如春佩抹,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背取董。 一陣腳步聲響...
    開(kāi)封第一講書人閱讀 31,967評(píng)論 1 265
  • 我被黑心中介騙來(lái)泰國(guó)打工棍苹, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人茵汰。 一個(gè)月前我還...
    沈念sama閱讀 46,315評(píng)論 2 360
  • 正文 我出身青樓枢里,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親蹂午。 傳聞我的和親對(duì)象是個(gè)殘疾皇子栏豺,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,486評(píng)論 2 348

推薦閱讀更多精彩內(nèi)容

  • 前言 本文基于Glide v3.7.0源碼分析,Glide v4.0大致流程和v3.7.0差不多豆胸,在一些技術(shù)細(xì)節(jié)上...
    事多店閱讀 16,170評(píng)論 8 17
  • 上篇我們以加載一張網(wǎng)絡(luò)圖片為例奥洼,講解了Glide加載一張圖片的整體流程。為了更連貫的理解流程我們略過(guò)了一些細(xì)節(jié)配乱,包...
    嘎啦果安卓獸閱讀 50,514評(píng)論 7 46
  • 【Android 庫(kù) Glide】 引用 Android圖片加載框架最全解析(一)溉卓,Glide的基本用法Andro...
    Rtia閱讀 5,408評(píng)論 0 22
  • Android緩存機(jī)制:如果沒(méi)有緩存,在大量的網(wǎng)絡(luò)請(qǐng)求從遠(yuǎn)程獲取圖片時(shí)會(huì)造成網(wǎng)絡(luò)流量的浪費(fèi)搬泥,加載速度較慢桑寨,用戶體驗(yàn)...
    芒果味的你呀閱讀 4,444評(píng)論 13 22
  • 從清晨的5:50出發(fā),去了里口山忿檩,去了茅草屋尉尾,非要去合(huo)慶,說(shuō)看了還可以再看一遍燥透,我說(shuō)漫天的霧看什么沙咏,她說(shuō)...
    smile絲嘜小主閱讀 97評(píng)論 0 0