提交 da7bc32c 编写于 作者: S Sam Judd

Apply transformations to cached resources.

This allows transformations to be applied that
for whatever reason cannot be cached. In 
particular this is required for transformations
for GIFs because neither Glide nor the Android
framework include a GIF decoder so we can only
cache the original data. This change is risky,
and relies on transformations being idempotent.
上级 063020db
......@@ -41,7 +41,7 @@ class DefaultResourceRunnerFactory implements ResourceRunnerFactory {
SourceResourceRunner<T, Z, R> sourceRunner = new SourceResourceRunner<T, Z, R>(key, width, height, fetcher,
decoder, transformation, encoder, transcoder, diskCache, priority, engineJob);
return new ResourceRunner<Z, R>(key, width, height, diskCache, cacheDecoder, transcoder, sourceRunner, service,
bgHandler, engineJob);
return new ResourceRunner<Z, R>(key, width, height, diskCache, cacheDecoder, transformation, transcoder,
sourceRunner, service, bgHandler, engineJob);
}
}
......@@ -6,8 +6,9 @@ import android.util.Log;
import com.bumptech.glide.Resource;
import com.bumptech.glide.load.Key;
import com.bumptech.glide.load.ResourceDecoder;
import com.bumptech.glide.load.resource.transcode.ResourceTranscoder;
import com.bumptech.glide.load.Transformation;
import com.bumptech.glide.load.engine.cache.DiskCache;
import com.bumptech.glide.load.resource.transcode.ResourceTranscoder;
import java.io.IOException;
import java.io.InputStream;
......@@ -23,6 +24,7 @@ public class ResourceRunner<Z, R> implements Runnable {
private static final String TAG = "ResourceRunner";
private final Key key;
private Transformation<Z> transformation;
private ResourceTranscoder<Z, R> transcoder;
private final SourceResourceRunner sourceRunner;
private final ExecutorService executorService;
......@@ -36,13 +38,15 @@ public class ResourceRunner<Z, R> implements Runnable {
private volatile boolean isCancelled;
public ResourceRunner(Key key, int width, int height, DiskCache diskCache,
ResourceDecoder<InputStream, Z> cacheDecoder, ResourceTranscoder<Z, R> transcoder,
SourceResourceRunner sourceRunner, ExecutorService executorService, Handler bgHandler, EngineJob job) {
ResourceDecoder<InputStream, Z> cacheDecoder, Transformation<Z> transformation,
ResourceTranscoder<Z, R> transcoder, SourceResourceRunner sourceRunner, ExecutorService executorService,
Handler bgHandler, EngineJob job) {
this.key = key;
this.width = width;
this.height = height;
this.diskCache = diskCache;
this.cacheDecoder = cacheDecoder;
this.transformation = transformation;
this.transcoder = transcoder;
this.sourceRunner = sourceRunner;
this.executorService = executorService;
......@@ -79,7 +83,11 @@ public class ResourceRunner<Z, R> implements Runnable {
Log.v(TAG, "loaded from disk cache in " + (SystemClock.currentThreadTimeMillis() - start));
}
if (fromCache != null) {
Resource<R> transcoded = transcoder.transcode(fromCache);
Resource<Z> transformed = transformation.transform(fromCache, width, height);
if (transformed != fromCache) {
fromCache.recycle();
}
Resource<R> transcoded = transcoder.transcode(transformed);
job.onResourceReady(transcoded);
} else {
future = executorService.submit(sourceRunner);
......
......@@ -4,8 +4,9 @@ import android.os.Handler;
import com.bumptech.glide.Resource;
import com.bumptech.glide.load.Key;
import com.bumptech.glide.load.ResourceDecoder;
import com.bumptech.glide.load.resource.transcode.ResourceTranscoder;
import com.bumptech.glide.load.Transformation;
import com.bumptech.glide.load.engine.cache.DiskCache;
import com.bumptech.glide.load.resource.transcode.ResourceTranscoder;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
......@@ -85,15 +86,28 @@ public class ResourceRunnerTest {
verify(harness.decoder).decode(eq(result), eq(harness.width), eq(harness.height));
}
@Test
public void testTransformationIsCalledIfCacheDecodeSucceeds() throws IOException {
InputStream is = new ByteArrayInputStream(new byte[0]);
when(harness.diskCache.get(eq(harness.key))).thenReturn(is);
when(harness.decoder.decode(eq(is), eq(harness.width), eq(harness.height))).thenReturn(harness.decoded);
harness.runner.run();
verify(harness.tranformation).transform(eq(harness.decoded), eq(harness.width), eq(harness.height));
}
@Test
public void testTranscoderIsCalledIfCacheDecodeSucceeds() throws IOException {
InputStream is = new ByteArrayInputStream(new byte[0]);
when(harness.diskCache.get(eq(harness.key))).thenReturn(is);
when(harness.decoder.decode(eq(is), eq(harness.width), eq(harness.height))).thenReturn(harness.decoded);
when(harness.tranformation.transform(eq(harness.decoded), eq(harness.width), eq(harness.height)))
.thenReturn(harness.transformed);
harness.runner.run();
verify(harness.transcoder).transcode(eq(harness.decoded));
verify(harness.transcoder).transcode(eq(harness.transformed));
}
@Test
......@@ -101,7 +115,10 @@ public class ResourceRunnerTest {
InputStream is = new ByteArrayInputStream(new byte[0]);
when(harness.diskCache.get(eq(harness.key))).thenReturn(is);
when(harness.decoder.decode(eq(is), eq(harness.width), eq(harness.height))).thenReturn(harness.decoded);
when(harness.transcoder.transcode(eq(harness.decoded))).thenReturn(harness.transcoded);
when(harness.tranformation.transform(eq(harness.decoded), eq(harness.width), eq(harness.height)))
.thenReturn(harness.transformed);
when(harness.transcoder
.transcode(eq(harness.transformed))).thenReturn(harness.transcoded);
harness.runner.run();
......@@ -113,12 +130,15 @@ public class ResourceRunnerTest {
InputStream is = new ByteArrayInputStream(new byte[0]);
when(harness.diskCache.get(eq(harness.key))).thenReturn(is);
when(harness.decoder.decode(eq(is), eq(harness.width), eq(harness.height))).thenReturn(harness.decoded);
when(harness.transcoder.transcode(eq(harness.decoded))).thenReturn(harness.transcoded);
when(harness.tranformation.transform(eq(harness.decoded), eq(harness.width), eq(harness.height)))
.thenReturn(harness.transformed);
when(harness.transcoder
.transcode(eq(harness.transformed))).thenReturn(harness.transcoded);
harness.runner.run();
verify(harness.decoded, never()).recycle();
verify(harness.decoded, never()).release();
verify(harness.transformed, never()).recycle();
verify(harness.transformed, never()).release();
}
@Test
......@@ -211,6 +231,32 @@ public class ResourceRunnerTest {
verify(harness.sourceFuture).cancel(anyBoolean());
}
@Test
public void testDecodedResourceIsRecycledIfTransformedResourceIsDifferent() throws IOException {
InputStream is = new ByteArrayInputStream(new byte[0]);
when(harness.diskCache.get(eq(harness.key))).thenReturn(is);
when(harness.decoder.decode(eq(is), eq(harness.width), eq(harness.height))).thenReturn(harness.decoded);
when(harness.tranformation.transform(eq(harness.decoded), eq(harness.width), eq(harness.height)))
.thenReturn(harness.transformed);
harness.runner.run();
verify(harness.decoded).recycle();
}
@Test
public void testDecodedResourceIsNotRecycledIfTransformedResourceIsDecodedResource() throws IOException {
InputStream is = new ByteArrayInputStream(new byte[0]);
when(harness.diskCache.get(eq(harness.key))).thenReturn(is);
when(harness.decoder.decode(eq(is), eq(harness.width), eq(harness.height))).thenReturn(harness.decoded);
when(harness.tranformation.transform(eq(harness.decoded), eq(harness.width), eq(harness.height)))
.thenReturn(harness.decoded);
harness.runner.run();
verify(harness.decoded, never()).recycle();
}
@SuppressWarnings("unchecked")
private static class ResourceRunnerHarness {
Key key = mock(Key.class);
......@@ -221,13 +267,15 @@ public class ResourceRunnerTest {
ExecutorService service = mock(ExecutorService.class);
EngineJob engineJob = mock(EngineJob.class);
Handler bgHandler = mock(Handler.class);
Transformation<Object> tranformation = mock(Transformation.class);
int width = 100;
int height = 100;
ResourceRunner<Object, Object> runner = new ResourceRunner(key, width, height, diskCache, decoder,
transcoder, sourceRunner, service, bgHandler, engineJob);
tranformation, transcoder, sourceRunner, service, bgHandler, engineJob);
Future future = mock(Future.class);
Future sourceFuture = mock(Future.class);
Resource<Object> decoded = mock(Resource.class);
Resource<Object> transformed = mock(Resource.class);
Resource<Object> transcoded = mock(Resource.class);
public ResourceRunnerHarness() {
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册