Skip to content

Commit

Permalink
Use factory to lazily instantiate disk cache.
Browse files Browse the repository at this point in the history
Fixes #298
  • Loading branch information
sjudd committed Dec 29, 2014
1 parent fad970a commit b7be7be
Show file tree
Hide file tree
Showing 7 changed files with 138 additions and 35 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -589,6 +589,7 @@ private static class Harness {
Transformation<Object> transformation = mock(Transformation.class);
ResourceTranscoder<Object, Object> transcoder = mock(ResourceTranscoder.class);
DiskCache diskCache = mock(DiskCache.class);
DecodeJob.DiskCacheProvider diskCacheProvider = mock(DecodeJob.DiskCacheProvider.class);
Priority priority = Priority.IMMEDIATE;

ResourceDecoder<File, Object> cacheDecoder = mock(ResourceDecoder.class);
Expand All @@ -614,11 +615,12 @@ public Harness(DiskCacheStrategy diskCacheStrategy) throws FileNotFoundException
when(loadProvider.getEncoder()).thenReturn(resultEncoder);
when(loadProvider.getSourceDecoder()).thenReturn(sourceDecoder);
when(loadProvider.getSourceEncoder()).thenReturn(sourceEncoder);
when(diskCacheProvider.getDiskCache()).thenReturn(diskCache);
}

public DecodeJob<Object, Object, Object> getJob() {
return new DecodeJob<Object, Object, Object>(key, width, height, dataFetcher, loadProvider, transformation,
transcoder, diskCache, diskCacheStrategy, priority, fileOpener);
transcoder, diskCacheProvider, diskCacheStrategy, priority, fileOpener);
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -487,7 +487,7 @@ public EngineTestHarness() {

job = mock(EngineJob.class);

engine = new Engine(cache, mock(DiskCache.class), mock(ExecutorService.class),
engine = new Engine(cache, mock(DiskCache.Factory.class), mock(ExecutorService.class),
mock(ExecutorService.class), jobs, keyFactory, activeResources, engineJobFactory, resourceRecycler);

}
Expand Down
43 changes: 28 additions & 15 deletions library/src/main/java/com/bumptech/glide/GlideBuilder.java
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,12 @@
import com.bumptech.glide.load.engine.bitmap_recycle.BitmapPoolAdapter;
import com.bumptech.glide.load.engine.bitmap_recycle.LruBitmapPool;
import com.bumptech.glide.load.engine.cache.DiskCache;
import com.bumptech.glide.load.engine.cache.DiskCacheAdapter;
import com.bumptech.glide.load.engine.cache.DiskLruCacheWrapper;
import com.bumptech.glide.load.engine.cache.InternalCacheDiskCacheFactory;
import com.bumptech.glide.load.engine.cache.LruResourceCache;
import com.bumptech.glide.load.engine.cache.MemoryCache;
import com.bumptech.glide.load.engine.cache.MemorySizeCalculator;
import com.bumptech.glide.load.engine.executor.FifoPriorityThreadPoolExecutor;

import java.io.File;
import java.util.concurrent.ExecutorService;

/**
Expand All @@ -28,10 +26,10 @@ public class GlideBuilder {
private Engine engine;
private BitmapPool bitmapPool;
private MemoryCache memoryCache;
private DiskCache diskCache;
private ExecutorService sourceService;
private ExecutorService diskCacheService;
private DecodeFormat decodeFormat;
private DiskCache.Factory diskCacheFactory;

public GlideBuilder(Context context) {
this.context = context.getApplicationContext();
Expand Down Expand Up @@ -65,11 +63,32 @@ public GlideBuilder setMemoryCache(MemoryCache memoryCache) {
* Sets the {@link com.bumptech.glide.load.engine.cache.DiskCache} implementation to use to store
* {@link com.bumptech.glide.load.engine.Resource} data and thumbnails.
*
* @deprecated Creating a disk cache directory on the main thread causes strict mode violations, use
* {@link #setDiskCache(com.bumptech.glide.load.engine.cache.DiskCache.Factory)} instead. Scheduled to be removed
* in Glide 4.0.
* @param diskCache The disk cache to use.
* @return This builder.
*/
public GlideBuilder setDiskCache(DiskCache diskCache) {
this.diskCache = diskCache;
@Deprecated
public GlideBuilder setDiskCache(final DiskCache diskCache) {
return setDiskCache(new DiskCache.Factory() {
@Override
public DiskCache build() {
return diskCache;
}
});
}

/**
* Sets the {@link com.bumptech.glide.load.engine.cache.DiskCache.Factory} implementation to use to construct
* the {@link com.bumptech.glide.load.engine.cache.DiskCache} to use to store
* {@link com.bumptech.glide.load.engine.Resource} data on disk.
*
* @param diskCacheFactory The disk cche factory to use.
* @return This builder.
*/
public GlideBuilder setDiskCache(DiskCache.Factory diskCacheFactory) {
this.diskCacheFactory = diskCacheFactory;
return this;
}

Expand Down Expand Up @@ -164,18 +183,12 @@ Glide createGlide() {
memoryCache = new LruResourceCache(calculator.getMemoryCacheSize());
}

if (diskCache == null) {
File cacheDir = Glide.getPhotoCacheDir(context);
if (cacheDir != null) {
diskCache = DiskLruCacheWrapper.get(cacheDir, Glide.DEFAULT_DISK_CACHE_SIZE);
}
if (diskCache == null) {
diskCache = new DiskCacheAdapter();
}
if (diskCacheFactory == null) {
diskCacheFactory = new InternalCacheDiskCacheFactory(context, Glide.DEFAULT_DISK_CACHE_SIZE);
}

if (engine == null) {
engine = new Engine(memoryCache, diskCache, diskCacheService, sourceService);
engine = new Engine(memoryCache, diskCacheFactory, diskCacheService, sourceService);
}

if (decodeFormat == null) {
Expand Down
25 changes: 15 additions & 10 deletions library/src/main/java/com/bumptech/glide/load/engine/DecodeJob.java
Original file line number Diff line number Diff line change
Expand Up @@ -38,33 +38,34 @@ class DecodeJob<A, T, Z> {
private final DataLoadProvider<A, T> loadProvider;
private final Transformation<T> transformation;
private final ResourceTranscoder<T, Z> transcoder;
private final DiskCacheProvider diskCacheProvider;
private final DiskCacheStrategy diskCacheStrategy;
private final DiskCache diskCache;
private final Priority priority;
private final FileOpener fileOpener;

private volatile boolean isCancelled;

public DecodeJob(EngineKey resultKey, int width, int height, DataFetcher<A> fetcher,
DataLoadProvider<A, T> loadProvider, Transformation<T> transformation, ResourceTranscoder<T, Z> transcoder,
DiskCache diskCache, DiskCacheStrategy diskCacheStrategy, Priority priority) {
this(resultKey, width, height, fetcher, loadProvider, transformation, transcoder, diskCache, diskCacheStrategy,
priority, DEFAULT_FILE_OPENER);
DiskCacheProvider diskCacheProvider, DiskCacheStrategy diskCacheStrategy, Priority priority) {
this(resultKey, width, height, fetcher, loadProvider, transformation, transcoder, diskCacheProvider,
diskCacheStrategy, priority, DEFAULT_FILE_OPENER);
}

// Visible for testing.
DecodeJob(EngineKey resultKey, int width, int height, DataFetcher<A> fetcher,
DataLoadProvider<A, T> loadProvider, Transformation<T> transformation, ResourceTranscoder<T, Z> transcoder,
DiskCache diskCache, DiskCacheStrategy diskCacheStrategy, Priority priority, FileOpener fileOpener) {
DiskCacheProvider diskCacheProvider, DiskCacheStrategy diskCacheStrategy, Priority priority, FileOpener
fileOpener) {
this.resultKey = resultKey;
this.width = width;
this.height = height;
this.fetcher = fetcher;
this.loadProvider = loadProvider;
this.transformation = transformation;
this.transcoder = transcoder;
this.diskCacheProvider = diskCacheProvider;
this.diskCacheStrategy = diskCacheStrategy;
this.diskCache = diskCache;
this.priority = priority;
this.fileOpener = fileOpener;
}
Expand Down Expand Up @@ -156,7 +157,7 @@ private void writeTransformedToCache(Resource<T> transformed) {
}
long startTime = LogTime.getLogTime();
SourceWriter<Resource<T>> writer = new SourceWriter<Resource<T>>(loadProvider.getEncoder(), transformed);
diskCache.put(resultKey, writer);
diskCacheProvider.getDiskCache().put(resultKey, writer);
if (Log.isLoggable(TAG, Log.VERBOSE)) {
logWithTimeAndKey("Wrote transformed from source to cache", startTime);
}
Expand Down Expand Up @@ -197,7 +198,7 @@ private Resource<T> decodeFromSourceData(A data) throws IOException {
private Resource<T> cacheAndDecodeSourceData(A data) throws IOException {
long startTime = LogTime.getLogTime();
SourceWriter<A> writer = new SourceWriter<A>(loadProvider.getSourceEncoder(), data);
diskCache.put(resultKey.getOriginalKey(), writer);
diskCacheProvider.getDiskCache().put(resultKey.getOriginalKey(), writer);
if (Log.isLoggable(TAG, Log.VERBOSE)) {
logWithTimeAndKey("Wrote source to cache", startTime);
}
Expand All @@ -211,7 +212,7 @@ private Resource<T> cacheAndDecodeSourceData(A data) throws IOException {
}

private Resource<T> loadFromCache(Key key) throws IOException {
File cacheFile = diskCache.get(key);
File cacheFile = diskCacheProvider.getDiskCache().get(key);
if (cacheFile == null) {
return null;
}
Expand All @@ -221,7 +222,7 @@ private Resource<T> loadFromCache(Key key) throws IOException {
result = loadProvider.getCacheDecoder().decode(cacheFile, width, height);
} finally {
if (result == null) {
diskCache.delete(key);
diskCacheProvider.getDiskCache().delete(key);
}
}
return result;
Expand Down Expand Up @@ -284,6 +285,10 @@ public boolean write(File file) {
}
}

interface DiskCacheProvider {
DiskCache getDiskCache();
}

static class FileOpener {
public OutputStream open(File file) throws FileNotFoundException {
return new BufferedOutputStream(new FileOutputStream(file));
Expand Down
40 changes: 32 additions & 8 deletions library/src/main/java/com/bumptech/glide/load/engine/Engine.java
Original file line number Diff line number Diff line change
Expand Up @@ -25,15 +25,17 @@
/**
* Responsible for starting loads and managing active and cached resources.
*/
public class Engine implements EngineJobListener, MemoryCache.ResourceRemovedListener, EngineResource.ResourceListener {
public class Engine implements EngineJobListener,
MemoryCache.ResourceRemovedListener,
EngineResource.ResourceListener {
private static final String TAG = "Engine";
private final Map<Key, EngineJob> jobs;
private final EngineKeyFactory keyFactory;
private final MemoryCache cache;
private final DiskCache diskCache;
private final EngineJobFactory engineJobFactory;
private final Map<Key, WeakReference<EngineResource<?>>> activeResources;
private final ResourceRecycler resourceRecycler;
private final LazyDiskCacheProvider diskCacheProvider;

// Lazily instantiate to avoid exceptions if Glide is initialized on a background thread. See #295.
private ReferenceQueue<EngineResource<?>> resourceReferenceQueue;
Expand All @@ -55,18 +57,18 @@ public void cancel() {
}
}

public Engine(MemoryCache memoryCache, DiskCache diskCache, ExecutorService diskCacheService,
public Engine(MemoryCache memoryCache, DiskCache.Factory diskCacheFactory, ExecutorService diskCacheService,
ExecutorService sourceService) {
this(memoryCache, diskCache, diskCacheService, sourceService, null, null, null, null, null);
this(memoryCache, diskCacheFactory, diskCacheService, sourceService, null, null, null, null, null);
}

// Visible for testing.
Engine(MemoryCache cache, DiskCache diskCache, ExecutorService diskCacheService, ExecutorService sourceService,
Map<Key, EngineJob> jobs, EngineKeyFactory keyFactory,
Engine(MemoryCache cache, DiskCache.Factory diskCacheFactory, ExecutorService diskCacheService,
ExecutorService sourceService, Map<Key, EngineJob> jobs, EngineKeyFactory keyFactory,
Map<Key, WeakReference<EngineResource<?>>> activeResources, EngineJobFactory engineJobFactory,
ResourceRecycler resourceRecycler) {
this.cache = cache;
this.diskCache = diskCache;
this.diskCacheProvider = new LazyDiskCacheProvider(diskCacheFactory);

if (activeResources == null) {
activeResources = new HashMap<Key, WeakReference<EngineResource<?>>>();
Expand Down Expand Up @@ -176,7 +178,7 @@ public <T, Z, R> LoadStatus load(Key signature, int width, int height, DataFetch

EngineJob engineJob = engineJobFactory.build(key, isMemoryCacheable);
DecodeJob<T, Z, R> decodeJob = new DecodeJob<T, Z, R>(key, width, height, fetcher, loadProvider, transformation,
transcoder, diskCache, diskCacheStrategy, priority);
transcoder, diskCacheProvider, diskCacheStrategy, priority);
EngineRunnable runnable = new EngineRunnable(engineJob, decodeJob, priority);
jobs.put(key, engineJob);
engineJob.addCallback(cb);
Expand Down Expand Up @@ -300,6 +302,28 @@ private ReferenceQueue<EngineResource<?>> getReferenceQueue() {
return resourceReferenceQueue;
}

private static class LazyDiskCacheProvider implements DecodeJob.DiskCacheProvider {

private final DiskCache.Factory factory;
private volatile DiskCache diskCache;

public LazyDiskCacheProvider(DiskCache.Factory factory) {
this.factory = factory;
}

@Override
public DiskCache getDiskCache() {
if (diskCache == null) {
synchronized (this) {
if (diskCache == null) {
diskCache = factory.build();
}
}
}
return diskCache;
}
}

private static class ResourceWeakReference extends WeakReference<EngineResource<?>> {
private final Key key;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,17 @@
* An interface for writing to and reading from a disk cache.
*/
public interface DiskCache {

/**
* An interface for lazily creating a disk cache.
*/
interface Factory {
/**
* Returns a new disk cache, or {@code null} if no disk cache could be created.
*/
DiskCache build();
}

/**
* An interface to actually write data to a key in the disk cache.
*/
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
package com.bumptech.glide.load.engine.cache;

import android.content.Context;

import com.bumptech.glide.Glide;

import java.io.File;

/**
* Creates an {@link com.bumptech.glide.disklrucache.DiskLruCache} based disk cache in the internal disk cache
* directory.
*/
public final class InternalCacheDiskCacheFactory implements DiskCache.Factory {
private final Context context;
private final String diskCacheName;
private final int diskCacheSize;

public InternalCacheDiskCacheFactory(Context context, int diskCacheSize) {
this(context, null /*diskCacheName*/, diskCacheSize);
}

public InternalCacheDiskCacheFactory(Context context, String diskCacheName, int diskCacheSize) {
this.context = context;
this.diskCacheName = diskCacheName;
this.diskCacheSize = diskCacheSize;
}

@Override
public DiskCache build() {
DiskCache diskCache = null;
final File cacheDir;

if (diskCacheName != null) {
cacheDir = Glide.getPhotoCacheDir(context, diskCacheName);
} else {
cacheDir = Glide.getPhotoCacheDir(context);
}

if (cacheDir != null) {
diskCache = DiskLruCacheWrapper.get(cacheDir, diskCacheSize);
}

if (diskCache == null) {
diskCache = new DiskCacheAdapter();
}
return diskCache;
}
}

0 comments on commit b7be7be

Please sign in to comment.