Glide緩存模塊源碼分析

在開始以前,咱們先了解Java中的四種引用和ReferenceQueue,爲何要了解這些知識呢?你們都知道Glide的緩存使用三級緩存,分別是磁盤緩存和兩級內存緩存,而Glide的兩級內存緩存就是用WeakReference+ReferenceQueue監控GC回收,這裏的回收是指JVM在合適的時間就會回收該對象。java

####Java的四種引用 熟悉Java的同窗都知道Java內存管理分爲內存分配和內存回收,都不須要咱們負責,垃圾回收的機制主要是看對象是否有引用指向該對象。java對象的引用包括 強引用、軟引用、弱引用和虛引用算法

  • 強引用(StrongReference) 強引用是指有引用變量指向時永遠不會被垃圾回收,JVM寧願拋出OOM錯誤也不會回收這種對象。緩存

  • 軟引用(SoftReference) 若是一個對象只具備軟引用,則內存空間足夠,注意是內存空間足夠,垃圾回收器就不會回收它;若是內存空間不足了,就會回收這些對象的內存。只要垃圾回收器沒有回收它,該對象就能夠被程序使用。軟引用可用來實現內存敏感的高速緩存,軟引用能夠和一個引用隊列(ReferenceQueue)聯合使用,若是軟引用所引用的對象被垃圾回收器回收,Java虛擬機就會把這個軟引用加入到與之關聯的引用隊列中,這也就提供給我監控對象是否被回收。網絡

  • 弱引用(WeakReference)
    弱引用與軟引用的區別在於:只具備弱引用的對象擁有更短暫的生命週期。在垃圾回收器線程掃描它所管轄的內存區域的過程當中,一旦發現了只具備弱引用的對象,無論當前內存空間足夠與否,都會回收它的內存。不過,因爲垃圾回收器是一個優先級很低的線程,所以不必定會很快發現那些只具備弱引用的對象,弱引用能夠和一個引用隊列(ReferenceQueue)聯合使用,若是弱引用所引用的對象被垃圾回收,Java虛擬機就會把這個弱引用加入到與之關聯的引用隊列中,這也就提供給我監控對象是否被回收。異步

  • 虛引用 虛引用顧名思義,就是形同虛設,與其餘幾種引用都不一樣,虛引用並不會決定對象的生命週期。若是一個對象僅持有虛引用,那麼它就和沒有任何引用同樣,在任什麼時候候均可能被垃圾回收器回收。虛引用主要用來跟蹤對象被垃圾回收器回收的活動。虛引用與軟引用和弱引用的一個區別在於:虛引用必須和引用隊列 (ReferenceQueue)聯合使用。當垃圾回收器準備回收一個對象時,若是發現它還有虛引用,就會在回收對象的內存以前,把這個虛引用加入到與之 關聯的引用隊列中。ide

這裏就舉個弱引用的栗子,其餘就不展開說明了?fetch

//引用隊列
 private ReferenceQueue queue = new ReferenceQueue<Person>();

/**
 * 監控對象被回收,由於若是被回收就會就如與之關聯的隊列中
 */
private void monitorClearedResources() {
    Log.e("tag", "start monitor");
    try {
        int n = 0;
        WeakReference k;
        while ((k = (WeakReference) queue.remove()) != null) {
            Log.e("tag", (++n) + "回收了:" + k + "   object: " + k.get());
        }
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
}



    new Thread() {
        @Override
        public void run() {
            monitorClearedResources();
        }
    }.start();


    new Thread() {
        @Override
        public void run() {
            while (true)
                new WeakReference<Person>(new Person("hahah"), queue);
        }
    }.start();
複製代碼

上面是一個監控對象回收,由於若是被回收就會就如與之關聯的隊列中,接着開啓線程製造觸發GC,並開啓線程監控對象回收,沒什麼好說的,下面就開始介紹Glide緩存。ui

####Glide緩存 Glide的緩存分爲了內存緩存和磁盤緩存,而內存緩存又分了兩個模塊,Glide緩存的設計思想很是好,不知道人家是怎麼想到。this

  • 內存緩存和磁盤緩存的做用各不相同 一、內存緩存主要是防止重複將圖片資源讀取到內存當中。 二、磁盤緩存主要是防止重複從網絡讀取數據。

內存緩存和磁盤緩存相互結合才構成了Glide極佳的圖片緩存效果,那麼接下來咱們就分別來分析一下這兩種緩存的使用方法以及它們的實現原理,看看我畫的時序圖,第一次畫時序圖,歡迎指教。 編碼

ClideCache.png

#####緩存Key 既然是緩存功能,那得有緩存的Key。那麼Glide的緩存Key是怎麼生成的呢?生成緩存Key的代碼在Engine類的load()方法中:

public synchronized <R> LoadStatus load(
        GlideContext glideContext, Object model,Key signature, int width,
        int height,  Class<?> resourceClass,Class<R> transcodeClass,
        Priority priority, DiskCacheStrategy diskCacheStrategy,
        Map<Class<?>, Transformation<?>> transformations,
        boolean isTransformationRequired, boolean isScaleOnlyOrNoTransform,
        Options options,  boolean isMemoryCacheable,
        boolean useUnlimitedSourceExecutorPool, boolean useAnimationPool,
        boolean onlyRetrieveFromCache, ResourceCallback cb,  Executor callbackExecutor) {

          //.....此處省略一萬行代碼

 EngineKey key = keyFactory.buildKey(model, signature, width,height,
         transformations,resourceClass, transcodeClass, options);

         //.....此處省略一萬行代碼
 }
複製代碼

實際上直接調用 keyFactory.buildKey方法並把一些資源表示相關的參數傳進去構建EngineKey ,那咱們來分析keyFactory.buildKey和EngineKey 的源碼:

EngineKeyFactory .buildKey:

class EngineKeyFactory {
EngineKey buildKey(Object model, Key signature, int width, int height,
  Map<Class<?>, Transformation<?>> transformations, Class<?> resourceClass,
  Class<?> transcodeClass, Options options) {
return new EngineKey(model, signature, width, height, transformations, resourceClass,
    transcodeClass, options);
    }
}
複製代碼

能夠看到EngineKeyFactory 的代碼並很少,僅僅是建立EngineKey實例,工廠方法模式,說實在Glid中用了好多工廠方法模式。

EngineKey :

class EngineKey implements Key {
  EngineKey( Object model,Key signature,  int width, int height,
  Map<Class<?>, Transformation<?>> transformations, Class<?> resourceClass,
  Class<?> transcodeClass,Options options) {
// 此處省略一萬行代碼
}

  @Override
public boolean equals(Object o) {
if (o instanceof EngineKey) {
  EngineKey other = (EngineKey) o;
  return model.equals(other.model)
      && signature.equals(other.signature)
      && height == other.height
      && width == other.width
      && transformations.equals(other.transformations)
      && resourceClass.equals(other.resourceClass)
      && transcodeClass.equals(other.transcodeClass)
      && options.equals(other.options);
}
    return false;
  }
@Override
  public int hashCode() {
if (hashCode == 0) {
  hashCode = model.hashCode();
  hashCode = 31 * hashCode + signature.hashCode();
  hashCode = 31 * hashCode + width;
  hashCode = 31 * hashCode + height;
  hashCode = 31 * hashCode + transformations.hashCode();
  hashCode = 31 * hashCode + resourceClass.hashCode();
  hashCode = 31 * hashCode + transcodeClass.hashCode();
  hashCode = 31 * hashCode + options.hashCode();
    }
return hashCode;
  }
  @Override
  public void updateDiskCacheKey(@NonNull MessageDigest messageDigest) {
    throw new UnsupportedOperationException();
  }
}
複製代碼

能夠看到,其實就是重寫equals()和hashCode()方法,即只有傳入EngineKey的全部參數都相同的狀況下才認爲是同一個EngineKey對象或者說是同一種資源。

####內存緩存 對於內存緩存的實現,你們應該最早想到的是LruCache算法(Least Recently Used),也叫近期最少使用算法。它的主要算法原理就是把最近使用的對象用強引用存儲在LinkedHashMap中,而且把最近最少使用的對象在緩存值達到預設定值以前從內存中移除,沒必要多說Glide也是使用了LruCache,可是Glide還結合WeakReference+ReferenceQueue機制。

對於Glide加載資源,那就從Engine.load()方法開始:

public synchronized <R> LoadStatus load(...............) {
    //構建緩存Key
    EngineKey key = keyFactory.buildKey();

    // 第一級內存緩存,資源是否正在使用,裏面使用WeakReference+ReferenceQueue機制
 1  EngineResource<?> active = loadFromActiveResources(key, isMemoryCacheable);
    if (active != null) {
        cb.onResourceReady(active, DataSource.MEMORY_CACHE);
        return null;
    }
    // 第二級內存緩存,裏面就是LruCache機制
 2   EngineResource<?> cached = loadFromCache(key, isMemoryCacheable);
    if (cached != null) {
        cb.onResourceReady(cached, DataSource.MEMORY_CACHE);
        return null;
    }

    // 不然開始異步加載,磁盤緩存或者請求額昂羅
    EngineJob<?> current = jobs.get(key, onlyRetrieveFromCache);
    if (current != null) {
        current.addCallback(cb, callbackExecutor);
        return new LoadStatus(cb, current);
    }

    EngineJob<R> engineJob = engineJobFactory.build(key, isMemoryCacheable, useUnlimitedSourceExecutorPool, useAnimationPool, onlyRetrieveFromCache);
    DecodeJob<R> decodeJob = decodeJobFactory.build(glideContext, model, key, signature,
            width, height, resourceClass, transcodeClass, priority, diskCacheStrategy,
            transformations, isTransformationRequired, isScaleOnlyOrNoTransform, onlyRetrieveFromCache,
            options, engineJob);

    jobs.put(key, engineJob);

    engineJob.addCallback(cb, callbackExecutor);

    // 開始執行任務
    engineJob.start(decodeJob);
    return new LoadStatus(cb, engineJob);
}
複製代碼

能夠看到,我標誌我1調用了 loadFromActiveResources()方法來獲取第一級緩存圖片,若是獲取到就直接調用cb.onResourceReady()方法進行回調。若是沒有獲取到,則會在我標誌我2調用loadFromCache()方法來獲取LruCache緩存圖片,獲取到的話也直接進行回調。只有在兩級緩存都沒有獲取到的狀況下,纔會繼續向下執行,從而開啓線程來加載圖片的任務。

也就是說,Glide的圖片加載過程當中會調用loadFromActiveResources()方法和loadFromCache()來獲取內存緩存。固然這兩個方法中一個使用的就是LruCache算法,另外一個使用的就是弱引用機制。咱們來看一下它們的源碼:

public class Engine implements EngineJobListener,
    MemoryCache.ResourceRemovedListener,
    EngineResource.ResourceListener {
  
 //.......此處省略一萬行代碼

  /**
    這個方法檢測資源是否正在使用
*/
@Nullable
private EngineResource<?> loadFromActiveResources(Key key, boolean isMemoryCacheable) {
    if (!isMemoryCacheable) {
        return null;
    }
    EngineResource<?> active = activeResources.get(key);
    if (active != null) {
        active.acquire();
    }
    return active;
}
private EngineResource<?> loadFromCache(Key key, boolean isMemoryCacheable) {
    if (!isMemoryCacheable) {
        return null;
    }

    // 在getEngineResourceFromCache方法中,會將已經存在內存緩存中的資源移除以後會加入activeResources緩存中
    EngineResource<?> cached = getEngineResourceFromCache(key);
    if (cached != null) {
        cached.acquire();
        activeResources.activate(key, cached);
    }
    return cached;
}

private EngineResource<?> getEngineResourceFromCache(Key key) {

    // 從LruCache中獲取並移除資源,可能會返回null
    Resource<?> cached = cache.remove(key);
    final EngineResource<?> result;

    //若是返回沒有資源,直接返回null
    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, /*isMemoryCacheable=*/ true, /*isRecyclable=*/ true, key, /*listener=*/ this);
    }
    return result;
}


 /**
 * 這個方法是在當資源從LruCache、disLruCache和網絡加載成功,將資源加入正在使用中
 *
 * @param engineJob
 * @param key
 * @param resource
 */
 public synchronized void onEngineJobComplete(
        EngineJob<?> engineJob, Key key, EngineResource<?> resource) {
    if (resource != null && resource.isMemoryCacheable()) {
        //當資源加載成功,將資源加入正在使用中,如:LruCache、disLruCache和網絡
        activeResources.activate(key, resource);
    }
}

 /**
 * 這個方法會在ActiveResource類中,正在使用的資源被清理時回調過來。
 * 而後從新把資源加入LruCache緩存中,後面會講ActiveResource的實現
 *
 * @param cacheKey
 * @param resource
 */
 @Override
public synchronized void onResourceReleased(Key cacheKey, EngineResource<?> resource) {
    activeResources.deactivate(cacheKey);
    if (resource.isMemoryCacheable()) {
        cache.put(cacheKey, resource);
    } else {
        resourceRecycler.recycle(resource);
    }
}
 //.......此處省略一萬行代碼

}
複製代碼

首先loadFromActiveResources方法檢測當前Key資源是否正在使用,若是存在直接 cb.onResourceReady()方法資源加載完成,不然調用loadFromCache從LruCache中獲取資源, 而後在getEngineResourceFromCache()方法中,會將已經存在內存緩存中的資源remove以後會加入activeResources緩存中.因此資源在內存中的緩存只能存在一份。

當咱們從LruResourceCache中獲取到緩存圖片以後會將它從緩存中移除,而後將緩存圖片存儲到activeResources當中。 activeResources就是一個弱引用的HashMap,用來緩存正在使用中的圖片,咱們能夠看到,loadFromActiveResources()方法就是從activeResources這個HashMap當中取值的。 使用activeResources來緩存正在使用中的圖片,能夠保護這些圖片不會被LruCache算法回收掉。 爲何會說能夠保護這些圖片不會被LruCache算法回收掉呢? 由於在ActiveResources中使用WeakReference+ReferenceQueue機制,監控GC回收,若是GC把資源回收,那麼ActiveResources 會被再次加入LruCache內存緩存中,從而起到了保護的做用。

當圖片加載完成以後,會在EngineJob當中對調用onResourceReady()方法:

@Override
  public void onResourceReady(Resource<R> resource, DataSource dataSource) {
synchronized (this) {
  this.resource = resource;
  this.dataSource = dataSource;
}
notifyCallbacksOfResult();
  }
複製代碼

接下來就是notifyCallbacksOfResult()方法

void notifyCallbacksOfResult() {
//......此處省略一萬行代碼

engineJobListener.onEngineJobComplete(this, localKey, localResource);

//......此處省略一萬行代碼
}
複製代碼

接着回調到Engine的onEngineJobComplete()方法當中,以下所示:

public synchronized void onEngineJobComplete(
        EngineJob<?> engineJob, Key key, EngineResource<?> resource) {
    // A null resource indicates that the load failed, usually due to an exception.
    if (resource != null && resource.isMemoryCacheable()) {
        //當資源加載成功,將資源加入正在使用中,如:LruCache、disLruCache和網絡
   1     activeResources.activate(key, resource);
    }

    jobs.removeIfCurrent(key, engineJob);
}
複製代碼

能夠看到我標誌1處,調用activeResources的activate方法把回調過來的EngineResourceactivate和Key做爲參數一塊兒傳入activeResources,就是這裏寫入緩存,固然在loadFromCache方法中也有寫入緩存: ActiveResources:

synchronized void activate(Key key, EngineResource<?> resource) {
    ResourceWeakReference toPut = new ResourceWeakReference(key, resource, resourceReferenceQueue, isActiveResourceRetentionAllowed);
    ResourceWeakReference removed = activeEngineResources.put(key, toPut);
    if (removed != null) {
        removed.reset();
    }
}
複製代碼

####ActiveResources 上面講了,當資源加載完成,回調到Engine的onEngineJobComplete(),並調用activeResources的activate方法把回調過來的EngineResourceactivate和Key做爲參數一塊兒傳入activeResources,那接下來分析ActiveResources:

final class ActiveResources {
private final boolean isActiveResourceRetentionAllowed;
// 監控GC回收資源線程池
private final Executor monitorClearedResourcesExecutor;


//使用強引用存儲ResourceWeakReference
@VisibleForTesting
final Map<Key, ResourceWeakReference> activeEngineResources = new HashMap<>();


//引用隊列與ResourceWeakReference配合監聽GC回收
private final ReferenceQueue<EngineResource<?>> resourceReferenceQueue = new ReferenceQueue<>();

private ResourceListener listener;

private volatile boolean isShutdown;
@Nullable
private volatile DequeuedResourceCallback cb;

ActiveResources(boolean isActiveResourceRetentionAllowed) {
    this(
            isActiveResourceRetentionAllowed,
            //啓動監控線程
            java.util.concurrent.Executors.newSingleThreadExecutor(
                    new ThreadFactory() {
                        @Override
                        public Thread newThread(@NonNull final Runnable r) {
                            return new Thread(
                                    new Runnable() {
                                        @Override
                                        public void run() {
                                            Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
                                            r.run();
                                        }
                                    },
                                    "glide-active-resources");
                        }
                    }));
}

@VisibleForTesting
ActiveResources(boolean isActiveResourceRetentionAllowed, Executor monitorClearedResourcesExecutor) {
    this.isActiveResourceRetentionAllowed = isActiveResourceRetentionAllowed;
    this.monitorClearedResourcesExecutor = monitorClearedResourcesExecutor;

    monitorClearedResourcesExecutor.execute(
            new Runnable() {
                @Override
                public void run() {
                    cleanReferenceQueue();
                }
            });
}

void setListener(ResourceListener listener) {
    synchronized (listener) {
        synchronized (this) {
            this.listener = listener;
        }
    }
}

/**
 * 資源加載完成調用此方法寫入緩存
 *
 * @param key
 * @param resource
 */
synchronized void activate(Key key, EngineResource<?> resource) {
    ResourceWeakReference toPut =
            new ResourceWeakReference(
                    key, resource, resourceReferenceQueue, isActiveResourceRetentionAllowed);

    ResourceWeakReference removed = activeEngineResources.put(key, toPut);
    if (removed != null) {
        removed.reset();
    }
}

/**
 * 移除指定Key的緩存
 *
 * @param key
 */
synchronized void deactivate(Key key) {
    ResourceWeakReference removed = activeEngineResources.remove(key);
    if (removed != null) {
        removed.reset();
    }
}


/**
 * 經過Key獲取緩存
 *
 * @param key
 * @return
 */
@Nullable
synchronized EngineResource<?> get(Key key) {
    ResourceWeakReference activeRef = activeEngineResources.get(key);
    if (activeRef == null) {
        return null;
    }

    EngineResource<?> active = activeRef.get();
    if (active == null) {
        cleanupActiveReference(activeRef);
    }
    return active;
}

@SuppressWarnings({"WeakerAccess", "SynchronizeOnNonFinalField"})
@Synthetic
void cleanupActiveReference(@NonNull ResourceWeakReference ref) {
    // Fixes a deadlock where we normally acquire the Engine lock and then the ActiveResources lock
    // but reverse that order in this one particular test. This is definitely a bit of a hack...
    synchronized (listener) {
        synchronized (this) {
            //將Reference移除HashMap強引用
            activeEngineResources.remove(ref.key);

            if (!ref.isCacheable || ref.resource == null) {
                return;
            }

            //從新構建新的資源
            EngineResource<?> newResource = new EngineResource<>(ref.resource,
                    /*isMemoryCacheable=*/ true,
                    /*isRecyclable=*/ false,
                    ref.key,
                    listener);

            // 若是資源被回收,有可能會回調Engine資源會被再次加入LruCache內存緩存中
            listener.onResourceReleased(ref.key, newResource);
        }
    }
}

@SuppressWarnings("WeakerAccess")
@Synthetic
void cleanReferenceQueue() {
    while (!isShutdown) {
        try {
            //remove會阻塞當前線程,知道GC回收,將ResourceWeakReference放入隊列
            ResourceWeakReference ref = (ResourceWeakReference) resourceReferenceQueue.remove();
            cleanupActiveReference(ref);

            // This section for testing only.
            DequeuedResourceCallback current = cb;
            if (current != null) {
                current.onResourceDequeued();
            }
            // End for testing only.
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        }
    }
}

@VisibleForTesting
void setDequeuedResourceCallback(DequeuedResourceCallback cb) {
    this.cb = cb;
}

@VisibleForTesting
interface DequeuedResourceCallback {
    void onResourceDequeued();
}

@VisibleForTesting
void shutdown() {
    isShutdown = true;
    if (monitorClearedResourcesExecutor instanceof ExecutorService) {
        ExecutorService service = (ExecutorService) monitorClearedResourcesExecutor;
        Executors.shutdownAndAwaitTermination(service);
    }
}

@VisibleForTesting
static final class ResourceWeakReference extends WeakReference<EngineResource<?>> {
    @SuppressWarnings("WeakerAccess")
    @Synthetic
    final Key key;
    @SuppressWarnings("WeakerAccess")
    @Synthetic
    final boolean isCacheable;

    @Nullable
    @SuppressWarnings("WeakerAccess")
    @Synthetic
    Resource<?> resource;

    @Synthetic
    @SuppressWarnings("WeakerAccess")
    ResourceWeakReference(@NonNull Key key, @NonNull EngineResource<?> referent, @NonNull ReferenceQueue<? super EngineResource<?>> queue, boolean isActiveResourceRetentionAllowed) {
        super(referent, queue);
        this.key = Preconditions.checkNotNull(key);
        this.resource = referent.isMemoryCacheable() && isActiveResourceRetentionAllowed ? Preconditions.checkNotNull(referent.getResource()) : null;
        isCacheable = referent.isMemoryCacheable();
    }

    void reset() {
        resource = null;
        /**
         * 調用此方法會將references加入與之關聯的ReferencesQueue隊列,固然這個方法有可能GC也會調用此方法清除references中的對象置爲null,
         * 因此這裏重寫WeakReference,使用一我的域保存資源,若是你經過get方法獲取對象一定爲null
         *
         *
         */
        clear();
    }
}
複製代碼

}

能夠看出在ActiveResources中使用Map保存ResourceWeakReference,即:使用強引用存儲ResourceWeakReference,而ResourceWeakReference繼承WeakReference,那麼爲何要從新拓展WeakReference呢?

你們知道文章開頭的時候我講那些知識並非多餘的,在ActiveResources中使用WeakReference+ReferenceQueue機制,監控GC回收,若是GC把資源回收,那麼會把WeakReference中的對象置爲null,並加入與之關聯的ReferenceQueue中,當你經過WeakReference.get()方法返回的是null,因此ResourceWeakReference拓展WeakReference的緣由就很明顯了,就是使用類的成員變量保存資源對象,若是你經過get方法獲取對象一定爲null。

####磁盤緩存

前面講過若是兩級內存緩存都沒有讀取到數據,那麼Glide就會開啓線程去加載資源,不限於網絡,也包括了磁盤:

public void onDataFetcherReady(Key sourceKey, Object data, DataFetcher<?> fetcher,
                               DataSource dataSource, Key attemptedKey) {
    this.currentSourceKey = sourceKey;// 保存數據的 key
    this.currentData = data;// 保存數據實體
    this.currentFetcher = fetcher; // 保存數據的獲取器
    this.currentDataSource = dataSource;// 數據來源: url 爲 REMOTE 類型的枚舉, 表示從遠程獲取
    this.currentAttemptingKey = attemptedKey;
    if (Thread.currentThread() != currentThread) {
        runReason = RunReason.DECODE_DATA;
        callback.reschedule(this);
    } else {
            // 調用 decodeFromRetrievedData 解析獲取的數據
            decodeFromRetrievedData();
    }
}
複製代碼

咱們知道Glide在兩級內存緩存沒有獲取到,那麼會開啓線程讀取加載圖片,當圖片加載成功,必然會回調onDataFetcherReady方法,然後調用decodeFromRetrievedData方法解析數據:

private void decodeFromRetrievedData() {
    Resource<R> resource = null;
    try {
        // 1. 調用了 decodeFromData 獲取資源,原始數據
        resource = decodeFromData(currentFetcher, currentData, currentDataSource);
    } catch (GlideException e) {
        e.setLoggingDetails(currentAttemptingKey, currentDataSource);
        throwables.add(e);
    }
    if (resource != null) {
        // 2. 通知外界資源獲取成功了
        notifyEncodeAndRelease(resource, currentDataSource);
    } else {
        runGenerators();
    }
}
複製代碼

decodeFromRetrievedData方法則是從原始數據中檢測是不是原始數據,若是不是則直接返回已經轉換事後的資源數據,若是當前data是原始數據,那麼Glide就會執行解碼以後再返回數據,可是若是是已經作過變換的數據,那麼直接調用notifyEncodeAndRelease方法通知上層資源獲取成功,咱們來看看notifyEncodeAndRelease方法:

private void notifyEncodeAndRelease(Resource<R> resource, DataSource dataSource) {

    Resource<R> result = resource;
    // 1. 回調上層資源準備好了,能夠展現
    notifyComplete(result, dataSource);
    stage = Stage.ENCODE;
        // 2. 將數據緩存到磁盤
        if (deferredEncodeManager.hasResourceToEncode()) {
            deferredEncodeManager.encode(diskCacheProvider, options);
        }
    onEncodeComplete();
}
複製代碼

能夠看到在notifyEncodeAndRelease方法中,首先就是直接調用 notifyComplete(result, dataSource)方法通知上層資源已經準備好了,接着調用onEngineJobComplete方法寫入內存緩存,而後 調用DeferredEncodeManager的encode方法進行編碼,將數據寫入磁盤,因此這裏應該就是磁盤緩存的地方:

void encode(DiskCacheProvider diskCacheProvider, Options options) {
        GlideTrace.beginSection("DecodeJob.encode");
        try {
            // 寫入磁盤緩存
            diskCacheProvider.getDiskCache().put(key, new DataCacheWriter<>(encoder, toEncode, options));
        } finally {
            toEncode.unlock();
            GlideTrace.endSection();
        }
    }
複製代碼

在encode方法中 diskCacheProvider.getDiskCache().put()寫入磁盤。

相關文章
相關標籤/搜索