提交 0be7fb30 编写于 作者: S Sam Judd

Check for original in cache before getting source.

上级 17326862
package com.bumptech.glide;
import com.bumptech.glide.load.Key;
import java.io.UnsupportedEncodingException;
import java.security.MessageDigest;
public class OriginalEngineKey implements Key {
private String id;
public OriginalEngineKey(String id) {
this.id = id;
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (!(o instanceof OriginalEngineKey)) {
return false;
}
OriginalEngineKey that = (OriginalEngineKey) o;
if (!id.equals(that.id)) {
return false;
}
return true;
}
@Override
public int hashCode() {
return id.hashCode();
}
@Override
public void updateDiskCacheKey(MessageDigest messageDigest) throws UnsupportedEncodingException {
messageDigest.update(id.getBytes("UTF-8"));
}
}
......@@ -30,15 +30,15 @@ class DefaultResourceRunnerFactory implements ResourceRunnerFactory {
}
@Override
public <T, Z, R> ResourceRunner<Z, R> build(Key key, int width, int height,
public <T, Z, R> ResourceRunner<Z, R> build(EngineKey key, int width, int height,
ResourceDecoder<InputStream, Z> cacheDecoder, DataFetcher<T> fetcher, ResourceDecoder<T, Z> decoder,
Transformation<Z> transformation, ResourceEncoder<Z> encoder, ResourceTranscoder<Z, R> transcoder,
Priority priority, boolean isMemoryCacheable, EngineJobListener listener) {
EngineJob engineJob = new EngineJob(key, mainHandler, isMemoryCacheable, listener);
SourceResourceRunner<T, Z, R> sourceRunner = new SourceResourceRunner<T, Z, R>(key, width, height, fetcher,
decoder, transformation, encoder, transcoder, diskCache, priority, engineJob);
SourceResourceRunner<T, Z, R> sourceRunner = new SourceResourceRunner<T, Z, R>(key, width, height, cacheLoader,
cacheDecoder, fetcher, decoder, transformation, encoder, transcoder, diskCache, priority, engineJob);
return new ResourceRunner<Z, R>(key, width, height, cacheLoader, cacheDecoder, transformation,
transcoder, sourceRunner, diskCacheService, service, engineJob, priority);
......
......@@ -27,7 +27,7 @@ public class Engine implements EngineJobListener, MemoryCache.ResourceRemovedLis
private static final String TAG = "Engine";
private final Map<Key, ResourceRunner> runners;
private final ResourceRunnerFactory factory;
private final KeyFactory keyFactory;
private final EngineKeyFactory keyFactory;
private final MemoryCache cache;
private final Map<Key, WeakReference<Resource>> activeResources;
private final ReferenceQueue<Resource> resourceReferenceQueue;
......@@ -52,7 +52,7 @@ public class Engine implements EngineJobListener, MemoryCache.ResourceRemovedLis
}
Engine(ResourceRunnerFactory factory, MemoryCache cache, DiskCache diskCache, ExecutorService resizeService,
ExecutorService diskCacheService, Map<Key, ResourceRunner> runners, KeyFactory keyFactory,
ExecutorService diskCacheService, Map<Key, ResourceRunner> runners, EngineKeyFactory keyFactory,
Map<Key, WeakReference<Resource>> activeResources) {
this.cache = cache;
......@@ -101,7 +101,8 @@ public class Engine implements EngineJobListener, MemoryCache.ResourceRemovedLis
long startTime = LogTime.getLogTime();
final String id = fetcher.getId();
Key key = keyFactory.buildKey(id, width, height, cacheDecoder, decoder, transformation, encoder, transcoder);
EngineKey key = keyFactory.buildKey(id, width, height, cacheDecoder, decoder, transformation, encoder,
transcoder);
Resource cached = cache.remove(key);
if (cached != null) {
......
package com.bumptech.glide.load.engine;
import com.bumptech.glide.OriginalEngineKey;
import com.bumptech.glide.load.Key;
import com.bumptech.glide.load.ResourceDecoder;
import com.bumptech.glide.load.ResourceEncoder;
......@@ -23,6 +24,7 @@ public class EngineKey implements Key {
private ResourceTranscoder transcoder;
private String stringKey;
private int hashCode;
private OriginalEngineKey originalKey;
public EngineKey(String id, int width, int height, ResourceDecoder cacheDecoder, ResourceDecoder decoder,
Transformation transformation, ResourceEncoder encoder, ResourceTranscoder transcoder) {
......@@ -36,6 +38,13 @@ public class EngineKey implements Key {
this.transcoder = transcoder;
}
public Key getOriginalKey() {
if (originalKey == null) {
originalKey = new OriginalEngineKey(id);
}
return originalKey;
}
@Override
public boolean equals(Object o) {
if (this == o) {
......
package com.bumptech.glide.load.engine;
import com.bumptech.glide.load.Key;
import com.bumptech.glide.load.ResourceDecoder;
import com.bumptech.glide.load.ResourceEncoder;
import com.bumptech.glide.load.Transformation;
import com.bumptech.glide.load.resource.transcode.ResourceTranscoder;
public class EngineKeyFactory implements KeyFactory {
@Override
public Key buildKey(String id, int width, int height, ResourceDecoder cacheDecoder, ResourceDecoder sourceDecoder,
public class EngineKeyFactory {
public EngineKey buildKey(String id, int width, int height, ResourceDecoder cacheDecoder, ResourceDecoder sourceDecoder,
Transformation transformation, ResourceEncoder encoder, ResourceTranscoder transcoder) {
return new EngineKey(id, width, height, cacheDecoder, sourceDecoder, transformation, encoder, transcoder);
}
}
package com.bumptech.glide.load.engine;
import com.bumptech.glide.load.Key;
import com.bumptech.glide.load.ResourceDecoder;
import com.bumptech.glide.load.ResourceEncoder;
import com.bumptech.glide.load.Transformation;
import com.bumptech.glide.load.resource.transcode.ResourceTranscoder;
public interface KeyFactory {
public Key buildKey(String id, int width, int height, ResourceDecoder cacheDecoder, ResourceDecoder sourceDecoder,
Transformation transformation, ResourceEncoder encoder, ResourceTranscoder transcoder);
}
......@@ -4,7 +4,6 @@ import android.os.SystemClock;
import android.util.Log;
import com.bumptech.glide.CacheLoader;
import com.bumptech.glide.Priority;
import com.bumptech.glide.load.Key;
import com.bumptech.glide.load.ResourceDecoder;
import com.bumptech.glide.load.Transformation;
import com.bumptech.glide.load.engine.executor.Prioritized;
......@@ -22,7 +21,7 @@ import java.util.concurrent.Future;
public class ResourceRunner<Z, R> implements Runnable, Prioritized {
private static final String TAG = "ResourceRunner";
private final Key key;
private final EngineKey key;
private final Transformation<Z> transformation;
private final ResourceTranscoder<Z, R> transcoder;
private final SourceResourceRunner sourceRunner;
......@@ -37,7 +36,7 @@ public class ResourceRunner<Z, R> implements Runnable, Prioritized {
private volatile Future<?> future;
private volatile boolean isCancelled;
public ResourceRunner(Key key, int width, int height, CacheLoader cacheLoader,
public ResourceRunner(EngineKey key, int width, int height, CacheLoader cacheLoader,
ResourceDecoder<InputStream, Z> cacheDecoder, Transformation<Z> transformation,
ResourceTranscoder<Z, R> transcoder, SourceResourceRunner sourceRunner, ExecutorService diskCacheService,
ExecutorService resizeService, EngineJob job, Priority priority) {
......
package com.bumptech.glide.load.engine;
import com.bumptech.glide.Priority;
import com.bumptech.glide.load.Key;
import com.bumptech.glide.load.ResourceDecoder;
import com.bumptech.glide.load.ResourceEncoder;
import com.bumptech.glide.load.Transformation;
import com.bumptech.glide.load.resource.transcode.ResourceTranscoder;
import com.bumptech.glide.load.data.DataFetcher;
import com.bumptech.glide.load.resource.transcode.ResourceTranscoder;
import java.io.InputStream;
......@@ -25,7 +24,7 @@ interface ResourceRunnerFactory {
* @param <R> The type of the resource that will be transcoded to from the decoded resource.
* @return
*/
public <T, Z, R> ResourceRunner<Z, R> build(Key key, int width, int height,
public <T, Z, R> ResourceRunner<Z, R> build(EngineKey key, int width, int height,
ResourceDecoder<InputStream, Z> cacheDecoder, DataFetcher<T> fetcher, ResourceDecoder<T, Z> decoder,
Transformation<Z> transformation, ResourceEncoder<Z> encoder, ResourceTranscoder<Z, R> transcoder,
Priority priority, boolean isMemoryCacheable, EngineJobListener listener);
......
......@@ -2,8 +2,8 @@ package com.bumptech.glide.load.engine;
import android.os.SystemClock;
import android.util.Log;
import com.bumptech.glide.CacheLoader;
import com.bumptech.glide.Priority;
import com.bumptech.glide.load.Key;
import com.bumptech.glide.load.ResourceDecoder;
import com.bumptech.glide.load.ResourceEncoder;
import com.bumptech.glide.load.Transformation;
......@@ -13,6 +13,7 @@ import com.bumptech.glide.load.engine.executor.Prioritized;
import com.bumptech.glide.load.resource.transcode.ResourceTranscoder;
import com.bumptech.glide.request.ResourceCallback;
import java.io.InputStream;
import java.io.OutputStream;
/**
......@@ -23,26 +24,32 @@ import java.io.OutputStream;
*/
public class SourceResourceRunner<T, Z, R> implements Runnable, DiskCache.Writer, Prioritized {
private static final String TAG = "SourceRunner";
private final Key key;
private final EngineKey key;
private final int width;
private final int height;
private CacheLoader cacheLoader;
private ResourceDecoder<InputStream, Z> cacheDecoder;
private final DataFetcher<T> fetcher;
private final ResourceDecoder<T, Z> decoder;
private Transformation<Z> transformation;
private final Transformation<Z> transformation;
private final ResourceEncoder<Z> encoder;
private ResourceTranscoder<Z, R> transcoder;
private DiskCache diskCache;
private Priority priority;
private ResourceCallback cb;
private final ResourceTranscoder<Z, R> transcoder;
private final DiskCache diskCache;
private final Priority priority;
private final ResourceCallback cb;
private Resource<Z> result;
private volatile boolean isCancelled;
public SourceResourceRunner(Key key, int width, int height, DataFetcher<T> dataFetcher,
ResourceDecoder<T, Z> decoder, Transformation<Z> transformation, ResourceEncoder<Z> encoder,
ResourceTranscoder<Z, R> transcoder, DiskCache diskCache, Priority priority, ResourceCallback cb) {
public SourceResourceRunner(EngineKey key, int width, int height, CacheLoader cacheLoader,
ResourceDecoder<InputStream, Z> cacheDecoder, DataFetcher<T> dataFetcher, ResourceDecoder<T, Z> decoder,
Transformation<Z> transformation, ResourceEncoder<Z> encoder, ResourceTranscoder<Z, R> transcoder,
DiskCache diskCache, Priority priority, ResourceCallback cb) {
this.key = key;
this.width = width;
this.height = height;
this.cacheLoader = cacheLoader;
this.cacheDecoder = cacheDecoder;
this.fetcher = dataFetcher;
this.decoder = decoder;
this.transformation = transformation;
......@@ -68,11 +75,16 @@ public class SourceResourceRunner<T, Z, R> implements Runnable, DiskCache.Writer
try {
long start = SystemClock.currentThreadTimeMillis();
final Resource<Z> decoded = decode();
if (Log.isLoggable(TAG, Log.VERBOSE)) {
Log.v(TAG, "Decoded from source in " + (SystemClock.currentThreadTimeMillis() - start));
start = SystemClock.currentThreadTimeMillis();
Resource<Z> decoded = cacheLoader.load(key.getOriginalKey(), cacheDecoder, width, height);
if (decoded == null) {
decoded = decodeFromSource();
if (Log.isLoggable(TAG, Log.VERBOSE)) {
Log.v(TAG, "Decoded from source in " + (SystemClock.currentThreadTimeMillis() - start));
start = SystemClock.currentThreadTimeMillis();
}
}
if (decoded != null) {
Resource<Z> transformed = transformation.transform(decoded, width, height);
if (decoded != transformed) {
......@@ -101,7 +113,7 @@ public class SourceResourceRunner<T, Z, R> implements Runnable, DiskCache.Writer
}
}
private Resource<Z> decode() throws Exception {
private Resource<Z> decodeFromSource() throws Exception {
try {
T toDecode = fetcher.loadData(priority);
if (toDecode != null) {
......
......@@ -17,6 +17,6 @@ public class UnitTranscoder implements ResourceTranscoder {
@Override
public String getId() {
return "UnitTranscoder.com.bumptech.glide.load.resource.transcode";
return "";
}
}
package com.bumptech.glide;
import org.junit.Test;
import java.io.UnsupportedEncodingException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Arrays;
import static junit.framework.Assert.assertEquals;
import static junit.framework.Assert.assertTrue;
public class OriginalEngineKeyTest {
@Test
public void testIsEqualToAnotherKeyWithSameId() {
String id = "fakeId";
OriginalEngineKey first = new OriginalEngineKey(id);
OriginalEngineKey second = new OriginalEngineKey(id);
assertEquals(first, second);
}
@Test
public void testReturnsSameHashCodeAsAnotherKeyWithSameId() {
String id = "testId";
OriginalEngineKey first = new OriginalEngineKey(id);
OriginalEngineKey second = new OriginalEngineKey(id);
assertEquals(first.hashCode(), second.hashCode());
}
@Test
public void testUpdatesDigestWithGivenId() throws NoSuchAlgorithmException, UnsupportedEncodingException {
String id = "testId2";
OriginalEngineKey firstKey = new OriginalEngineKey(id);
MessageDigest firstDigest = MessageDigest.getInstance("SHA-1");
firstKey.updateDiskCacheKey(firstDigest);
byte[] firstBytes = firstDigest.digest();
OriginalEngineKey secondKey = new OriginalEngineKey(id);
MessageDigest secondDigest = MessageDigest.getInstance("SHA-1");
secondKey.updateDiskCacheKey(secondDigest);
byte[] secondBytes = secondDigest.digest();
assertTrue(Arrays.equals(firstBytes, secondBytes));
}
}
package com.bumptech.glide.load;
import com.bumptech.glide.load.engine.Resource;
import org.junit.Test;
import static junit.framework.Assert.assertEquals;
import static org.mockito.Mockito.mock;
public class UnitTransformationTest {
@Test
public void testReturnsGivenResource() {
Resource resource = mock(Resource.class);
UnitTransformation transformation = UnitTransformation.get();
assertEquals(resource, transformation.transform(resource, 10, 10));
}
@Test
public void testHasEmptyId() {
assertEquals("", UnitTransformation.get().getId());
}
}
\ No newline at end of file
......@@ -2,7 +2,6 @@ package com.bumptech.glide.load.engine;
import android.os.Handler;
import com.bumptech.glide.Priority;
import com.bumptech.glide.load.Key;
import com.bumptech.glide.load.ResourceDecoder;
import com.bumptech.glide.load.ResourceEncoder;
import com.bumptech.glide.load.Transformation;
......@@ -56,7 +55,7 @@ public class DefaultResourceRunnerFactoryTest {
boolean isMemoryCacheable;
public ResourceRunner build() {
return factory.build(mock(Key.class), width, height, cacheDecoder, fetcher, decoder, transformation,
return factory.build(mock(EngineKey.class), width, height, cacheDecoder, fetcher, decoder, transformation,
encoder, mock(ResourceTranscoder.class), priority, isMemoryCacheable, listener);
}
}
......
......@@ -378,8 +378,8 @@ public class EngineTest {
@SuppressWarnings("unchecked")
private static class EngineTestHarness {
Key cacheKey = mock(Key.class);
KeyFactory keyFactory = mock(KeyFactory.class);
EngineKey cacheKey = mock(EngineKey.class);
EngineKeyFactory keyFactory = mock(EngineKeyFactory.class);
ResourceDecoder<InputStream, Object> cacheDecoder = mock(ResourceDecoder.class);
DataFetcher<Object> fetcher = mock(DataFetcher.class);
ResourceDecoder<Object, Object> decoder = mock(ResourceDecoder.class);
......
......@@ -178,7 +178,8 @@ public class ResourceRunnerTest {
@SuppressWarnings("unchecked")
private static class ResourceRunnerHarness {
Key key = mock(Key.class);
EngineKey key = mock(EngineKey.class);
Key originalKey = mock(Key.class);
ResourceDecoder<InputStream, Object> decoder = mock(ResourceDecoder.class);
SourceResourceRunner<Object, Object, Object> sourceRunner = mock(SourceResourceRunner.class);
ResourceTranscoder<Object, Object> transcoder = mock(ResourceTranscoder.class);
......@@ -200,6 +201,7 @@ public class ResourceRunnerTest {
public ResourceRunnerHarness() {
when(key.toString()).thenReturn(ID);
when(key.getOriginalKey()).thenReturn(originalKey);
when(resizeService.submit(eq(runner))).thenReturn(future);
when(resizeService.submit(eq(sourceRunner))).thenReturn(sourceFuture);
when(cacheLoader.load(eq(key), eq(decoder), eq(width), eq(height))).thenReturn(decoded);
......
package com.bumptech.glide.load.engine;
import com.bumptech.glide.CacheLoader;
import com.bumptech.glide.Priority;
import com.bumptech.glide.load.Key;
import com.bumptech.glide.load.ResourceDecoder;
......@@ -12,6 +13,8 @@ import com.bumptech.glide.request.ResourceCallback;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.stubbing.Answer;
import org.robolectric.RobolectricTestRunner;
import java.io.ByteArrayInputStream;
......@@ -28,6 +31,7 @@ import static org.mockito.Matchers.anyInt;
import static org.mockito.Matchers.anyObject;
import static org.mockito.Matchers.eq;
import static org.mockito.Matchers.isNull;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
......@@ -43,7 +47,53 @@ public class SourceResourceRunnerTest {
}
@Test
public void testResourceFetcherIsCalled() throws Exception {
public void testCacheLoaderIsCalledWithOriginalKey() {
harness.runner.run();
verify(harness.cacheLoader).load(eq(harness.originalKey), eq(harness.cacheDecoder), eq(harness.width),
eq(harness.height));
}
@Test
public void testIfCacheLoaderReturnsOriginalResourceFetcherIsNotCalled() throws Exception {
when(harness.cacheLoader.load(eq(harness.originalKey), eq(harness.cacheDecoder), eq(harness.width),
eq(harness.height))).thenReturn(harness.decoded);
harness.runner.run();
verify(harness.fetcher, never()).loadData(any(Priority.class));
}
@Test
public void testIfCacheLoaderReturnsOriginalResourceThenOriginalResourceIsTransformedAndReturned() {
when(harness.cacheLoader.load(eq(harness.originalKey), eq(harness.cacheDecoder), eq(harness.width),
eq(harness.height))).thenReturn(harness.decoded);
harness.runner.run();
verify(harness.cb).onResourceReady(eq(harness.transcoded));
}
@Test
public void testEncoderIsCalledWithTransformedIfOriginalResourceInCache() {
when(harness.cacheLoader.load(eq(harness.originalKey), eq(harness.cacheDecoder), eq(harness.width),
eq(harness.height))).thenReturn(harness.decoded);
final OutputStream expected = new ByteArrayOutputStream();
doAnswer(new Answer<Object>() {
@Override
public Object answer(InvocationOnMock invocation) throws Throwable {
harness.runner.write(expected);
return null;
}
}).when(harness.diskCache).put(eq(harness.key), eq(harness.runner));
harness.runner.run();
verify(harness.encoder).encode(eq(harness.transformed), eq(expected));
}
@Test
public void testResourceFetcherIsCalledIfOriginalNotInCache() throws Exception {
harness.runner.run();
verify(harness.fetcher).loadData(eq(harness.priority));
......@@ -82,7 +132,7 @@ public class SourceResourceRunnerTest {
harness.runner.run();
harness.runner.write(expected);
verify(harness.encoder).encode(eq(harness.decoded), eq(expected));
verify(harness.encoder).encode(eq(harness.transformed), eq(expected));
}
@Test
......@@ -146,6 +196,8 @@ public class SourceResourceRunnerTest {
InputStream is = new ByteArrayInputStream(new byte[0]);
when(harness.fetcher.loadData(eq(harness.priority))).thenReturn(is);
when(harness.decoder.decode(eq(is), eq(harness.width), eq(harness.height))).thenReturn(harness.decoded);
when(harness.transformation.transform(eq(harness.decoded), eq(harness.width), eq(harness.height)))
.thenReturn(harness.decoded);
harness.runner.run();
......@@ -204,6 +256,8 @@ public class SourceResourceRunnerTest {
@SuppressWarnings("unchecked")
private static class SourceResourceHarness {
CacheLoader cacheLoader = mock(CacheLoader.class);
ResourceDecoder<InputStream, Object> cacheDecoder = mock(ResourceDecoder.class);
DataFetcher<Object> fetcher = mock(DataFetcher.class);
ResourceDecoder<Object, Object> decoder = mock(ResourceDecoder.class);
ResourceEncoder<Object> encoder = mock(ResourceEncoder.class);
......@@ -212,16 +266,22 @@ public class SourceResourceRunnerTest {
Priority priority = Priority.LOW;
ResourceCallback cb = mock(ResourceCallback.class);
Resource<Object> decoded = mock(Resource.class);
Resource<Object> transformed = mock(Resource.class);
Resource<Object> transcoded = mock(Resource.class);
Transformation<Object> transformation = mock(Transformation.class);
int width = 150;
int height = 200;
EngineKey key = mock(EngineKey.class);
Key originalKey = mock(Key.class);
SourceResourceRunner<Object, Object, Object> runner = new SourceResourceRunner<Object, Object, Object>(
mock(Key.class), width, height, fetcher, decoder, transformation, encoder, transcoder, diskCache,
priority, cb);
key, width, height, cacheLoader, cacheDecoder, fetcher, decoder, transformation, encoder, transcoder,
diskCache, priority, cb);
public SourceResourceHarness() {
when(transformation.transform(eq(decoded), eq(width), eq(height))).thenReturn(decoded);
when(key.getOriginalKey()).thenReturn(originalKey);
when(transformation.transform(eq(decoded), eq(width), eq(height))).thenReturn(transformed);
when(transcoder.transcode(eq(transformed))).thenReturn(transcoded);
}
}
}
package com.bumptech.glide.load.resource.transcode;
import com.bumptech.glide.load.engine.Resource;
import com.bumptech.glide.tests.Util;
import org.junit.Test;
import static junit.framework.Assert.assertEquals;
......@@ -18,8 +17,7 @@ public class UnitTranscoderTest {
}
@Test
public void testHasValidId() {
Util.assertClassHasValidId(UnitTranscoder.class, UnitTranscoder.get().getId());
public void testHasEmptyId() {
assertEquals("", UnitTranscoder.get().getId());
}
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册