package com.bumptech.glide.load.engine; import com.bumptech.glide.load.DataSource; import com.bumptech.glide.load.Key; import com.bumptech.glide.load.data.DataFetcher; import com.bumptech.glide.load.model.ModelLoader; import com.bumptech.glide.load.model.ModelLoader.LoadData; import java.io.File; import java.util.List; /** * Generates {@link com.bumptech.glide.load.data.DataFetcher DataFetchers} from cache files * containing original unmodified source data. */ class DataCacheGenerator implements DataFetcherGenerator, DataFetcher.DataCallback<Object> { private List<Key> cacheKeys; private final DecodeHelper<?> helper; private final FetcherReadyCallback cb; private int sourceIdIndex = -1; private Key sourceKey; private List<ModelLoader<File, ?>> modelLoaders; private int modelLoaderIndex; private volatile LoadData<?> loadData; // PMD is wrong here, this File must be an instance variable because it may be used across // multiple calls to startNext. @SuppressWarnings("PMD.SingularField") private File cacheFile; DataCacheGenerator(DecodeHelper<?> helper, FetcherReadyCallback cb) { this(helper.getCacheKeys(), helper, cb); } // In some cases we may want to load a specific cache key (when loading from source written to // cache), so we accept a list of keys rather than just obtain the list from the helper. DataCacheGenerator(List<Key> cacheKeys, DecodeHelper<?> helper, FetcherReadyCallback cb) { this.cacheKeys = cacheKeys; this.helper = helper; this.cb = cb; } @Override public boolean startNext() { while (modelLoaders == null || !hasNextModelLoader()) { sourceIdIndex++; if (sourceIdIndex >= cacheKeys.size()) { return false; } Key sourceId = cacheKeys.get(sourceIdIndex); Key originalKey = new DataCacheKey(sourceId, helper.getSignature()); cacheFile = helper.getDiskCache().get(originalKey); if (cacheFile != null) { this.sourceKey = sourceId; modelLoaders = helper.getModelLoaders(cacheFile); modelLoaderIndex = 0; } } loadData = null; boolean started = false; while (!started && hasNextModelLoader()) { ModelLoader<File, ?> modelLoader = modelLoaders.get(modelLoaderIndex++); loadData = modelLoader.buildLoadData(cacheFile, helper.getWidth(), helper.getHeight(), helper.getOptions()); if (loadData != null && helper.hasLoadPath(loadData.fetcher.getDataClass())) { started = true; loadData.fetcher.loadData(helper.getPriority(), this); } } return started; } private boolean hasNextModelLoader() { return modelLoaderIndex < modelLoaders.size(); } @Override public void cancel() { LoadData<?> local = loadData; if (local != null) { local.fetcher.cancel(); } } @Override public void onDataReady(Object data) { cb.onDataFetcherReady(sourceKey, data, loadData.fetcher, DataSource.DATA_DISK_CACHE, sourceKey); } @Override public void onLoadFailed(Exception e) { cb.onDataFetcherFailed(sourceKey, e, loadData.fetcher, DataSource.DATA_DISK_CACHE); } }