Skip to content

Commit

Permalink
Add an exception handler to Glide requests
Browse files Browse the repository at this point in the history
Fixes #26
  • Loading branch information
Sam Judd committed Oct 20, 2013
1 parent 5578379 commit f83b7e5
Show file tree
Hide file tree
Showing 2 changed files with 109 additions and 1 deletion.
92 changes: 91 additions & 1 deletion library/src/com/bumptech/glide/Glide.java
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,67 @@ public class Glide {

private ImageManager imageManager = null;

/**
* A class for handling exceptions that occur while loading images
*
* @param <T> The type of the model being loaded
*/
public static abstract class ExceptionHandler<T> {

/**
* 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.
*
* <p>
* It is safe to reload this or a different model or change what is displayed in the target at this point.
* For example:
* <pre>
* <code>
* public void onException(Exception e, T model, Target target) {
* target.setPlaceholder(R.drawable.a_specific_error_for_my_exception);
* Glide.load(model).into(target);
* }
* </code>
* </pre>
* </p>
*
* <p>
* 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).
* </p>
*
* @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}
*
* <p>
* 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.
* </p>
*/
@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.
*
Expand Down Expand Up @@ -423,6 +484,7 @@ public static class Request<T> {
private int errorId = -1;
private Downsampler downsampler = Downsampler.AT_LEAST;
private ArrayList<TransformationLoader<T>> transformationLoaders = new ArrayList<TransformationLoader<T>>();
private ExceptionHandler<T> exceptionHandler;

private Request(T model) {
this(model, GLIDE.getFactory(model));
Expand Down Expand Up @@ -569,6 +631,19 @@ public Request<T> 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<T> exception(ExceptionHandler<T> exceptionHandler) {
this.exceptionHandler = exceptionHandler;

return this;
}

/**
* Start loading the image into the view.
*
Expand Down Expand Up @@ -641,7 +716,7 @@ private ImagePresenter<T> getImagePresenter(Target target) {
return result;
}

private ImagePresenter<T> buildImagePresenter(Target target) {
private ImagePresenter<T> buildImagePresenter(final Target target) {
TransformationLoader<T> transformationLoader = getFinalTransformationLoader();

ImagePresenter.Builder<T> builder = new ImagePresenter.Builder<T>()
Expand Down Expand Up @@ -670,6 +745,17 @@ public void onImageReady(Target target, boolean fromCache) {
builder.setErrorResource(errorId);
}

if (exceptionHandler != null) {
builder.setExceptionHandler(new ImagePresenter.ExceptionHandler<T>() {
@Override
public void onException(Exception e, T model, boolean isCurrent) {
if (isCurrent) {
exceptionHandler.onException(e, model, target);
}
}
});
}

return builder.build();
}

Expand Down Expand Up @@ -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();
Expand All @@ -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
Expand All @@ -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;
}
Expand Down
18 changes: 18 additions & 0 deletions library/tests/src/com/bumptech/glide/GlideTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -213,6 +214,23 @@ public void testDifferentErrorIdsReplacesPresenter() {
);
}

public void testDifferentExceptionHandlersReplacesPresenter() {
assertDifferentPresenters(
Glide.load("a").exception(new Glide.ExceptionHandler<String>() {

@Override
public void onException(Exception e, String model, Target target) {

}
}),
Glide.load("a").exception(new Glide.ExceptionHandler<String>() {
@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();
Expand Down

0 comments on commit f83b7e5

Please sign in to comment.