blob: 98ec65ecf0b6ead8401e9b83834126f87de647fe [file] [log] [blame]
package com.bumptech.glide.load.engine;
import android.util.Log;
import com.bumptech.glide.Priority;
import com.bumptech.glide.load.engine.executor.Prioritized;
import com.bumptech.glide.request.ResourceCallback;
/**
* A runnable class responsible for using an {@link com.bumptech.glide.load.engine.DecodeJob} to decode resources on a
* background thread in two stages.
*
* <p>
* In the first stage, this class attempts to decode a resource
* from cache, first using transformed data and then using source data. If no resource can be decoded from cache,
* this class then requests to be posted again. During the second stage this class then attempts to use the
* {@link com.bumptech.glide.load.engine.DecodeJob} to decode data directly from the original source.
* </p>
*
* <p>
* Using two stages with a re-post in between allows us to run fast disk cache decodes on one thread and slow source
* fetches on a second pool so that loads for local data are never blocked waiting for loads for remote data to
* complete.
* </p>
*/
class EngineRunnable implements Runnable, Prioritized {
private static final String TAG = "EngineRunnable";
private final Priority priority;
private final EngineRunnableManager manager;
private final DecodeJob<?, ?, ?> decodeJob;
private Stage stage;
private volatile boolean isCancelled;
public EngineRunnable(EngineRunnableManager manager, DecodeJob<?, ?, ?> decodeJob, Priority priority) {
this.manager = manager;
this.decodeJob = decodeJob;
this.stage = Stage.CACHE;
this.priority = priority;
}
public void cancel() {
isCancelled = true;
decodeJob.cancel();
}
@Override
public void run() {
if (isCancelled) {
return;
}
Exception exception = null;
Resource<?> resource = null;
try {
resource = decode();
} catch (Exception e) {
if (Log.isLoggable(TAG, Log.VERBOSE)) {
Log.v(TAG, "Exception decoding", e);
}
exception = e;
}
if (isCancelled) {
if (resource != null) {
resource.recycle();
}
return;
}
if (resource == null) {
onLoadFailed(exception);
} else {
onLoadComplete(resource);
}
}
private boolean isDecodingFromCache() {
return stage == Stage.CACHE;
}
private void onLoadComplete(Resource resource) {
manager.onResourceReady(resource);
}
private void onLoadFailed(Exception e) {
if (isDecodingFromCache()) {
stage = Stage.SOURCE;
manager.submitForSource(this);
} else {
manager.onException(e);
}
}
private Resource<?> decode() throws Exception {
if (isDecodingFromCache()) {
return decodeFromCache();
} else {
return decodeFromSource();
}
}
private Resource<?> decodeFromCache() throws Exception {
Resource<?> result = null;
try {
result = decodeJob.decodeResultFromCache();
} catch (Exception e) {
if (Log.isLoggable(TAG, Log.DEBUG)) {
Log.d(TAG, "Exception decoding result from cache: " + e);
}
}
if (result == null) {
result = decodeJob.decodeSourceFromCache();
}
return result;
}
private Resource<?> decodeFromSource() throws Exception {
return decodeJob.decodeFromSource();
}
@Override
public int getPriority() {
return priority.ordinal();
}
private enum Stage {
/** Attempting to decode resource from cache. */
CACHE,
/** Attempting to decode resource from source data. */
SOURCE
}
interface EngineRunnableManager extends ResourceCallback {
void submitForSource(EngineRunnable runnable);
}
}