From f83b7e59356f490c19d154d29b1007ff82f58a06 Mon Sep 17 00:00:00 2001
From: Sam Judd
Date: Sun, 20 Oct 2013 13:14:13 -0700
Subject: [PATCH] Add an exception handler to Glide requests
Fixes #26
---
library/src/com/bumptech/glide/Glide.java | 92 ++++++++++++++++++-
.../src/com/bumptech/glide/GlideTest.java | 18 ++++
2 files changed, 109 insertions(+), 1 deletion(-)
diff --git a/library/src/com/bumptech/glide/Glide.java b/library/src/com/bumptech/glide/Glide.java
index 724441a88c..65c3576b90 100644
--- a/library/src/com/bumptech/glide/Glide.java
+++ b/library/src/com/bumptech/glide/Glide.java
@@ -54,6 +54,67 @@ public class Glide {
private ImageManager imageManager = null;
+ /**
+ * A class for handling exceptions that occur while loading images
+ *
+ * @param The type of the model being loaded
+ */
+ public static abstract class ExceptionHandler {
+
+ /**
+ * Called when an exception occurs during a load. Will only be called if we currently want to display an image
+ * for the given model in the given target. It is recommended to create a single instance per activity/fragment
+ * rather than instantiate a new object for each call to {@code Glide.load()} to avoid object churn.
+ *
+ *
+ * It is safe to reload this or a different model or change what is displayed in the target at this point.
+ * For example:
+ *
+ *
+ * public void onException(Exception e, T model, Target target) {
+ * target.setPlaceholder(R.drawable.a_specific_error_for_my_exception);
+ * Glide.load(model).into(target);
+ * }
+ *
+ *
+ *
+ *
+ *
+ * Note - if you want to reload this or any other model after an exception, you will need to include all
+ * relevant builder calls (like centerCrop, placeholder etc).
+ *
+ *
+ * @param e The exception, or null
+ * @param model The model we were trying to load when the exception occured
+ * @param target The {@link Target} we were trying to load the image into
+ */
+ public abstract void onException(Exception e, T model, Target target);
+
+ /**
+ * {@inheritDoc}
+ *
+ *
+ * By default we only check the both objects are not null and that their classes are identical. This assumes
+ * that two instances of the same anonymous inner class will behave identically.
+ *
+ */
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+
+ return true;
+ }
+
+ /**
+ * {@inheritDoc }
+ */
+ @Override
+ public int hashCode() {
+ throw new UnsupportedOperationException();
+ }
+ }
+
/**
* Get the singleton.
*
@@ -423,6 +484,7 @@ public static class Request {
private int errorId = -1;
private Downsampler downsampler = Downsampler.AT_LEAST;
private ArrayList> transformationLoaders = new ArrayList>();
+ private ExceptionHandler exceptionHandler;
private Request(T model) {
this(model, GLIDE.getFactory(model));
@@ -569,6 +631,19 @@ public Request error(int resourceId) {
return this;
}
+ /**
+ * Sets an exception handler to use if a load fails. Note it's best to create a single instance of an exception
+ * handler per activity/fragment rather than pass one in per request.
+ *
+ * @param exceptionHandler The exception handler to use
+ * @return This request
+ */
+ public Request exception(ExceptionHandler exceptionHandler) {
+ this.exceptionHandler = exceptionHandler;
+
+ return this;
+ }
+
/**
* Start loading the image into the view.
*
@@ -641,7 +716,7 @@ private ImagePresenter getImagePresenter(Target target) {
return result;
}
- private ImagePresenter buildImagePresenter(Target target) {
+ private ImagePresenter buildImagePresenter(final Target target) {
TransformationLoader transformationLoader = getFinalTransformationLoader();
ImagePresenter.Builder builder = new ImagePresenter.Builder()
@@ -670,6 +745,17 @@ public void onImageReady(Target target, boolean fromCache) {
builder.setErrorResource(errorId);
}
+ if (exceptionHandler != null) {
+ builder.setExceptionHandler(new ImagePresenter.ExceptionHandler() {
+ @Override
+ public void onException(Exception e, T model, boolean isCurrent) {
+ if (isCurrent) {
+ exceptionHandler.onException(e, model, target);
+ }
+ }
+ });
+ }
+
return builder.build();
}
@@ -732,6 +818,7 @@ private static class Metadata {
private final String downsamplerId;
private final String transformationId;
+ private final ExceptionHandler exceptionHandler;
public Metadata(Request request) {
modelClass = request.model.getClass();
@@ -741,6 +828,7 @@ public Metadata(Request request) {
animationId = request.animationId;
placeholderId = request.placeholderId;
errorId = request.errorId;
+ exceptionHandler = request.exceptionHandler;
}
//we don't want to change behavior in sets/maps, just be able to compare properties
@@ -753,6 +841,8 @@ public boolean isIdenticalTo(Metadata metadata) {
if (!modelClass.equals(metadata.modelClass)) return false;
if (!modelLoaderClass.equals(metadata.modelLoaderClass)) return false;
if (!transformationId.equals(metadata.transformationId)) return false;
+ if (exceptionHandler == null ? metadata.exceptionHandler != null :
+ !exceptionHandler.equals(metadata.exceptionHandler)) return false;
return true;
}
diff --git a/library/tests/src/com/bumptech/glide/GlideTest.java b/library/tests/src/com/bumptech/glide/GlideTest.java
index bde7a89a34..b543950a56 100644
--- a/library/tests/src/com/bumptech/glide/GlideTest.java
+++ b/library/tests/src/com/bumptech/glide/GlideTest.java
@@ -8,6 +8,7 @@
import com.bumptech.glide.loader.stream.StreamLoader;
import com.bumptech.glide.presenter.ImagePresenter;
import com.bumptech.glide.presenter.target.ImageViewTarget;
+import com.bumptech.glide.presenter.target.Target;
import com.bumptech.glide.tests.R;
import java.io.File;
@@ -213,6 +214,23 @@ public void testDifferentErrorIdsReplacesPresenter() {
);
}
+ public void testDifferentExceptionHandlersReplacesPresenter() {
+ assertDifferentPresenters(
+ Glide.load("a").exception(new Glide.ExceptionHandler() {
+
+ @Override
+ public void onException(Exception e, String model, Target target) {
+
+ }
+ }),
+ Glide.load("a").exception(new Glide.ExceptionHandler() {
+ @Override
+ public void onException(Exception e, String model, Target target) {
+ }
+ })
+ );
+ }
+
private void assertDifferentPresenters(Glide.Request a, Glide.Request b) {
a.into(imageView);
ImagePresenter first = getImagePresenterFromView();