Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add an exception handler to Glide requests #30

Merged
merged 2 commits into from
Nov 7, 2013
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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();
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why throw an UnsupportedOperationException() ?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To be sure that I don't accidentally use the method somewhere. It's basically undefined behavior, these things shouldn't be used in hash maps unless someone explicitly adds an implementation for the method in a subclass.

}
}

/**
* 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