1package com.bumptech.glide.load.engine; 2 3import android.os.SystemClock; 4import android.util.Log; 5import com.bumptech.glide.load.CacheLoader; 6import com.bumptech.glide.Priority; 7import com.bumptech.glide.load.Encoder; 8import com.bumptech.glide.load.ResourceDecoder; 9import com.bumptech.glide.load.ResourceEncoder; 10import com.bumptech.glide.load.Transformation; 11import com.bumptech.glide.load.data.DataFetcher; 12import com.bumptech.glide.load.engine.cache.DiskCache; 13import com.bumptech.glide.load.engine.executor.Prioritized; 14import com.bumptech.glide.load.resource.transcode.ResourceTranscoder; 15import com.bumptech.glide.request.ResourceCallback; 16 17import java.io.InputStream; 18import java.io.OutputStream; 19 20/** 21 * 22 * @param <T> The type of the data the resource will be decoded from. 23 * @param <Z> The type of the resource that will be decoded. 24 * @param <R> The type of the resource that will be transcoded to from the decoded resource. 25 */ 26public class SourceResourceRunner<T, Z, R> implements Runnable, DiskCache.Writer, Prioritized { 27 private static final String TAG = "SourceRunner"; 28 private final EngineKey key; 29 private final int width; 30 private final int height; 31 private final CacheLoader cacheLoader; 32 private final ResourceDecoder<InputStream, Z> cacheDecoder; 33 private final DataFetcher<T> fetcher; 34 private final boolean cacheSource; 35 private final Encoder<T> sourceEncoder; 36 private final ResourceDecoder<T, Z> decoder; 37 private final Transformation<Z> transformation; 38 private final ResourceEncoder<Z> encoder; 39 private final ResourceTranscoder<Z, R> transcoder; 40 private final DiskCache diskCache; 41 private final Priority priority; 42 private final ResourceCallback cb; 43 44 private Resource<Z> result; 45 private volatile boolean isCancelled; 46 47 public SourceResourceRunner(EngineKey key, int width, int height, CacheLoader cacheLoader, 48 ResourceDecoder<InputStream, Z> cacheDecoder, DataFetcher<T> dataFetcher, boolean cacheSource, 49 Encoder<T> sourceEncoder, ResourceDecoder<T, Z> decoder, Transformation<Z> transformation, 50 ResourceEncoder<Z> encoder, ResourceTranscoder<Z, R> transcoder, DiskCache diskCache, Priority priority, 51 ResourceCallback cb) { 52 this.key = key; 53 this.width = width; 54 this.height = height; 55 this.cacheLoader = cacheLoader; 56 this.cacheDecoder = cacheDecoder; 57 this.fetcher = dataFetcher; 58 this.cacheSource = cacheSource; 59 this.sourceEncoder = sourceEncoder; 60 this.decoder = decoder; 61 this.transformation = transformation; 62 this.encoder = encoder; 63 this.transcoder = transcoder; 64 this.diskCache = diskCache; 65 this.priority = priority; 66 this.cb = cb; 67 } 68 69 public void cancel() { 70 isCancelled = true; 71 if (fetcher != null) { 72 fetcher.cancel(); 73 } 74 } 75 76 @Override 77 public void run() { 78 if (isCancelled) { 79 return; 80 } 81 82 try { 83 long start = SystemClock.currentThreadTimeMillis(); 84 Resource<Z> decoded = cacheLoader.load(key.getOriginalKey(), cacheDecoder, width, height); 85 86 if (decoded == null) { 87 decoded = decodeFromSource(); 88 if (Log.isLoggable(TAG, Log.VERBOSE)) { 89 Log.v(TAG, "Decoded from source in " + (SystemClock.currentThreadTimeMillis() - start) + " cache"); 90 start = SystemClock.currentThreadTimeMillis(); 91 } 92 } 93 94 if (decoded != null) { 95 Resource<Z> transformed = transformation.transform(decoded, width, height); 96 if (decoded != transformed) { 97 decoded.recycle(); 98 } 99 result = transformed; 100 } 101 if (Log.isLoggable(TAG, Log.VERBOSE)) { 102 Log.v(TAG, "transformed in " + (SystemClock.currentThreadTimeMillis() - start)); 103 } 104 105 if (result != null) { 106 diskCache.put(key, this); 107 start = SystemClock.currentThreadTimeMillis(); 108 Resource<R> transcoded = transcoder.transcode(result); 109 if (Log.isLoggable(TAG, Log.VERBOSE)) { 110 Log.d(TAG, "transcoded in " + (SystemClock.currentThreadTimeMillis() - start)); 111 } 112 cb.onResourceReady(transcoded); 113 } else { 114 cb.onException(null); 115 } 116 117 } catch (Exception e) { 118 cb.onException(e); 119 } 120 } 121 122 private Resource<Z> encodeSourceAndDecodeFromCache(final T data) { 123 diskCache.put(key.getOriginalKey(), new DiskCache.Writer() { 124 @Override 125 public boolean write(OutputStream os) { 126 return sourceEncoder.encode(data, os); 127 } 128 }); 129 return cacheLoader.load(key.getOriginalKey(), cacheDecoder, width, height); 130 } 131 132 private Resource<Z> decodeFromSource() throws Exception { 133 try { 134 final T data = fetcher.loadData(priority); 135 if (data != null) { 136 if (cacheSource) { 137 return encodeSourceAndDecodeFromCache(data); 138 } else { 139 return decoder.decode(data, width, height); 140 } 141 } 142 } finally { 143 fetcher.cleanup(); 144 } 145 146 return null; 147 } 148 149 @Override 150 public boolean write(OutputStream os) { 151 long start = SystemClock.currentThreadTimeMillis(); 152 boolean success = encoder.encode(result, os); 153 if (Log.isLoggable(TAG, Log.VERBOSE)) { 154 Log.v(TAG, "wrote to disk cache in " + (SystemClock.currentThreadTimeMillis() - start)); 155 } 156 return success; 157 } 158 159 @Override 160 public int getPriority() { 161 return priority.ordinal(); 162 } 163} 164