glide快取
分為記憶體快取以及硬碟快取,記憶體快取又分為lruresourchcache和弱引用快取。
快取的key,引數很多,通過equals和hashcode演算法來判斷是否是同一個key.
先是從loadFromCache裡面讀取,內部程式碼先是從cache裡面移除,新增到弱引用的資源裡面。LinkedHashMap, LruCache 實現了MemoryCache。如果cache裡面沒有這條資料,從loadFromActiveResources裡面讀取。還是沒有資料,從網路獲取。
對於記憶體快取,正在使用的圖片使用弱引用快取,不在使用的圖片使用lrucache來進行快取。
為啥使用弱引用快取:防止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()); //記憶體快取讀取儲存的資料 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; } //記憶體的弱引用當中讀取資料 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); } //網路獲取資料 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); } //從快取讀取資料 private EngineResource<?> loadFromCache(Key key, boolean isMemoryCacheable) { if (!isMemoryCacheable) { return null; } EngineResource<?> cached = getEngineResourceFromCache(key); if (cached != null) { cached.acquire(); //新增資料到弱引用當中 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()方法中,資料寫入記憶體,先是寫入到弱引用快取當中,
資料寫入記憶體:根據一個int資料,作為這張圖片當前被使用的次數,當這個計數器>0的時候,是在弱引用裡面,當這個計數器==0的時候,呼叫一個回撥,將資料從弱引用移除掉,新增到lrucache裡面。通過這個計數器來判斷是寫入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); } }
網路獲取的時候,先是從硬碟讀取資料,硬盤裡面先是從result裡面讀取,如果沒有,再從source裡面讀取!
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(); } } //硬碟讀取資料 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; } //網路讀取資料 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); } }
硬碟讀取資料,會分為DiskCacheStrategy.SOURCE和DiskCacheStrategy.RESULT兩種。在DecodeJob類當中。
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對圖片進行硬碟快取
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; }