Home | History | Annotate | Download | only in engine
      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 
     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 
     44     public void cancel() {
     45         isCancelled = true;
     46         decodeJob.cancel();
     47     }
     48 
     49     @Override
     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 
     80     private boolean isDecodingFromCache() {
     81         return stage == Stage.CACHE;
     82     }
     83 
     84     private void onLoadComplete(Resource resource) {
     85         manager.onResourceReady(resource);
     86     }
     87 
     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 
     97     private Resource<?> decode() throws Exception {
     98         if (isDecodingFromCache()) {
     99             return decodeFromCache();
    100         } else {
    101             return decodeFromSource();
    102         }
    103     }
    104 
    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 
    121     private Resource<?> decodeFromSource() throws Exception {
    122         return decodeJob.decodeFromSource();
    123     }
    124 
    125     @Override
    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 {
    138         void submitForSource(EngineRunnable runnable);
    139     }
    140 }
    141