1 package com.bumptech.glide.load.engine; 2 3 import android.util.Log; 4 5 import com.bumptech.glide.Priority; 6 import com.bumptech.glide.load.engine.executor.Prioritized; 7 import com.bumptech.glide.request.ResourceCallback; 8 9 /** 10 * A runnable class responsible for using an {@link com.bumptech.glide.load.engine.DecodeJob} to decode resources on a 11 * background thread in two stages. 12 * 13 * <p> 14 * In the first stage, this class attempts to decode a resource 15 * from cache, first using transformed data and then using source data. If no resource can be decoded from cache, 16 * this class then requests to be posted again. During the second stage this class then attempts to use the 17 * {@link com.bumptech.glide.load.engine.DecodeJob} to decode data directly from the original source. 18 * </p> 19 * 20 * <p> 21 * Using two stages with a re-post in between allows us to run fast disk cache decodes on one thread and slow source 22 * fetches on a second pool so that loads for local data are never blocked waiting for loads for remote data to 23 * complete. 24 * </p> 25 */ 26 class EngineRunnable implements Runnable, Prioritized { 27 private static final String TAG = "EngineRunnable"; 28 29 private final Priority priority; 30 private final EngineRunnableManager manager; 31 private final DecodeJob<?, ?, ?> decodeJob; 32 33 private Stage stage; 34 35 private volatile boolean isCancelled; 36 EngineRunnable(EngineRunnableManager manager, DecodeJob<?, ?, ?> decodeJob, Priority priority)37 public EngineRunnable(EngineRunnableManager manager, DecodeJob<?, ?, ?> decodeJob, Priority priority) { 38 this.manager = manager; 39 this.decodeJob = decodeJob; 40 this.stage = Stage.CACHE; 41 this.priority = priority; 42 } 43 cancel()44 public void cancel() { 45 isCancelled = true; 46 decodeJob.cancel(); 47 } 48 49 @Override run()50 public void run() { 51 if (isCancelled) { 52 return; 53 } 54 55 Exception exception = null; 56 Resource<?> resource = null; 57 try { 58 resource = decode(); 59 } catch (Exception e) { 60 if (Log.isLoggable(TAG, Log.VERBOSE)) { 61 Log.v(TAG, "Exception decoding", e); 62 } 63 exception = e; 64 } 65 66 if (isCancelled) { 67 if (resource != null) { 68 resource.recycle(); 69 } 70 return; 71 } 72 73 if (resource == null) { 74 onLoadFailed(exception); 75 } else { 76 onLoadComplete(resource); 77 } 78 } 79 isDecodingFromCache()80 private boolean isDecodingFromCache() { 81 return stage == Stage.CACHE; 82 } 83 onLoadComplete(Resource resource)84 private void onLoadComplete(Resource resource) { 85 manager.onResourceReady(resource); 86 } 87 onLoadFailed(Exception e)88 private void onLoadFailed(Exception e) { 89 if (isDecodingFromCache()) { 90 stage = Stage.SOURCE; 91 manager.submitForSource(this); 92 } else { 93 manager.onException(e); 94 } 95 } 96 decode()97 private Resource<?> decode() throws Exception { 98 if (isDecodingFromCache()) { 99 return decodeFromCache(); 100 } else { 101 return decodeFromSource(); 102 } 103 } 104 decodeFromCache()105 private Resource<?> decodeFromCache() throws Exception { 106 Resource<?> result = null; 107 try { 108 result = decodeJob.decodeResultFromCache(); 109 } catch (Exception e) { 110 if (Log.isLoggable(TAG, Log.DEBUG)) { 111 Log.d(TAG, "Exception decoding result from cache: " + e); 112 } 113 } 114 115 if (result == null) { 116 result = decodeJob.decodeSourceFromCache(); 117 } 118 return result; 119 } 120 decodeFromSource()121 private Resource<?> decodeFromSource() throws Exception { 122 return decodeJob.decodeFromSource(); 123 } 124 125 @Override getPriority()126 public int getPriority() { 127 return priority.ordinal(); 128 } 129 130 private enum Stage { 131 /** Attempting to decode resource from cache. */ 132 CACHE, 133 /** Attempting to decode resource from source data. */ 134 SOURCE 135 } 136 137 interface EngineRunnableManager extends ResourceCallback { submitForSource(EngineRunnable runnable)138 void submitForSource(EngineRunnable runnable); 139 } 140 } 141