Glide3:engine.load() ,內(nèi)存緩存的實現(xiàn)細節(jié)

engine.load() 實際的圖片加載。

loadStatus = engine.load(signature, width, height, dataFetcher, loadProvider, transformation, transcoder,
priority, isMemoryCacheable, diskCacheStrategy, this);

//Engine.java
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(); //圖片唯一標識
    // 不同的寬高,對應不同的EngineKey,實際就是緩存中的key值。
    EngineKey key = keyFactory.buildKey(id, signature, width, height, loadProvider.getCacheDecoder(),
            loadProvider.getSourceDecoder(), transformation, loadProvider.getEncoder(),
            transcoder, loadProvider.getSourceEncoder());
    // 一、從緩存中獲取圖片1,從memoryCache中后去圖片資源。
    EngineResource<?> cached = loadFromCache(key, isMemoryCacheable);
    if (cached != null) {
        cb.onResourceReady(cached); //調(diào)用callback的方法,回調(diào)。
        if (Log.isLoggable(TAG, Log.VERBOSE)) {
            logWithTimeAndKey("Loaded resource from cache", startTime, key);
        }
        return null;
    }
    // 二.從緩存中獲取圖片2
    EngineResource<?> active = loadFromActiveResources(key, isMemoryCacheable);
    if (active != null) {
        cb.onResourceReady(active);//調(diào)用callback的方法,回調(diào)。
        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ò) EngineRunnable獲取圖片。
    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);
}

緩存

-內(nèi)存緩存:防止圖片重復讀取到內(nèi)存中 LruCache (近期最少使用的算法); 內(nèi)存緩存,還有一種【弱引用】機制 來實現(xiàn)。
LruCache原理:把最近使用對象的強引用,存儲在LinkHashMap上 ,并且最近最少使用的對象,
在緩存池 達到預設(shè)值之前, 從內(nèi)存中移除。

    private final MemoryCache cache;
    private final Map<Key, WeakReference<EngineResource<?>>> activeResources;
    EngineResource<?> cached = loadFromCache(key, isMemoryCacheable); //緩存的圖片
    它的內(nèi)部使用的是 LinkedHashMap 實現(xiàn),
    
    EngineResource<?> active = loadFromActiveResources(key, isMemoryCacheable);//正在使用的圖片
    //HashMap 弱引用保存值。
//loadFromActiveResources()
 private EngineResource<?> loadFromActiveResources(Key key, boolean isMemoryCacheable) {
    if (!isMemoryCacheable) {
        return null;
    }
    EngineResource<?> active = null;
    WeakReference<EngineResource<?>> activeRef = activeResources.get(key);//通過弱引用獲取
    if (activeRef != null) {
        active = activeRef.get();
        if (active != null) {
            active.acquire();
        } else {
            activeResources.remove(key);
        }
    }
    return active;
}
private EngineResource<?> loadFromCache(Key key, boolean isMemoryCacheable) {
    if (!isMemoryCacheable) { 
        return null;
    }
    EngineResource<?> cached = getEngineResourceFromCache(key);
    if (cached != null) {
        cached.acquire();
        //存入緩存中。hashmap保存 到緩存中。
        activeResources.put(key, new ResourceWeakReference(key, cached, getReferenceQueue()));
    }
    return cached;
}
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;
}

內(nèi)存緩存的寫入工作。

cb.onResourceReady(cached);
--> EngineJob.java
public void onResourceReady(final Resource<?> resource) {
    this.resource = resource;
    MAIN_THREAD_HANDLER.obtainMessage(MSG_COMPLETE, this).sendToTarget();
}
// private static final Handler MAIN_THREAD_HANDLER = new Handler(Looper.getMainLooper(), new MainThreadCallback());
  private static class MainThreadCallback implements Handler.Callback {

    @Override
    public boolean handleMessage(Message message) {
        if (MSG_COMPLETE == message.what || MSG_EXCEPTION == message.what) {
            EngineJob job = (EngineJob) message.obj;
            if (MSG_COMPLETE == message.what) {
                job.handleResultOnMainThread();
            } else {
                job.handleExceptionOnMainThread();
            }
            return true;
        }
        return false;
    }
  }
--> 
    private void handleResultOnMainThread() {
        if (isCancelled) { //任務取消
            resource.recycle();
            return;
        } else if (cbs.isEmpty()) {
            throw new IllegalStateException("Received a resource without any callbacks to notify");
        }
        engineResource = engineResourceFactory.build(resource, isCacheable);
        hasResource = true;
        engineResource.acquire(); //圖片引用統(tǒng)計
        listener.onEngineJobComplete(key, engineResource); //回調(diào)方法

        for (ResourceCallback cb : cbs) {
            if (!isInIgnoredCallbacks(cb)) {
                engineResource.acquire();//圖片引用統(tǒng)計
                cb.onResourceReady(engineResource);
            }
        }
        // Our request is complete, so we can release the resource.
        engineResource.release();
    }
// 內(nèi)存緩存加入。EngineResource.java 
// acquire(), release() 
@Override
public void onResourceReleased(Key cacheKey, EngineResource resource) {
    Util.assertMainThread();
    activeResources.remove(cacheKey);
    if (resource.isCacheable()) {
        cache.put(cacheKey, resource);//加入lruCache 緩存
    } else {
        resourceRecycler.recycle(resource);
    }
}   
    
    
//Engine.java    
@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);
}    

-硬盤緩存:防止重復從網(wǎng)絡(luò)/硬盤上 復制下載 讀取圖片。

-------------End-------------------------

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關(guān)閱讀更多精彩內(nèi)容

  • 在早期的Android開發(fā)中,圖片加載其實一直是個比較麻煩的問題。我們在處理圖片時會遇到各種各樣的問題:內(nèi)存溢出、...
    小小的coder閱讀 238評論 0 0
  • Glide的介紹與使用 Glide是一個非常強大、優(yōu)秀的圖片加載框架,不但使用簡單,而且加入了Activity和F...
    Aisen閱讀 2,595評論 0 0
  • 【Android 庫 Glide】 引用 Android圖片加載框架最全解析(一),Glide的基本用法Andro...
    Rtia閱讀 5,890評論 0 22
  • 先看下Glide官方文檔對圖片加載性能優(yōu)化的兩個方面: 圖片解碼速度 解碼圖片帶來的資源壓力 主要采用的步驟如下:...
    柬埔沒有寨閱讀 708評論 0 2
  • 寫在前面 這篇文章是個人參考源碼及博客編寫的筆記,主要是對源碼簡單分析。都是個人對源碼的見解記錄下來,只是介紹流程...
    其實小吳人挺好閱讀 500評論 0 2

友情鏈接更多精彩內(nèi)容