Search code examples
javaandroidimageimage-resizingandroid-glide

Why do I need all these empty methods to create a custom file target for Glide?


I am using Glide for resizing an image and saving it to the file system in an Android app, and I've created a custom FileTarget class that extends Glide's native Target to do it.

It works. Yay! But I'm sort of appalled by all the empty methods I had to 'define' to get it to satisfy the Target implementation. All I really care about is onResourceReady...

Is there any way to implement this without declaring all these empty methods? Should I be worried that they're all like this?

I'm a little new to Android so I appreciate your patience.

    public static class FileTarget<T extends Bitmap> implements Target<Bitmap> {
    private final int width;
    private final int height;

    String fileName;
    Bitmap.CompressFormat format;
    int quality;

    public FileTarget(int width, int height, String fileName, Bitmap.CompressFormat format, int quality) {
        this.width = width;
        this.height = height;
        this.fileName = fileName;
        this.format = format;
        this.quality = quality;
    }

    @Override
    public void onLoadStarted(Drawable drawable) {}

    @Override
    public void onLoadFailed(Drawable drawable) {}

    @Override
    public void onLoadCleared(Drawable drawable) {}

    @Override
    public void getSize(SizeReadyCallback cb) {
        cb.onSizeReady(width, height);
    }

    @Override
    public void removeCallback(@NonNull SizeReadyCallback cb) {}

    @Override
    public void setRequest(@Nullable Request request) {}

    @Nullable
    @Override
    public Request getRequest() {
        return null;
    }

    @Override
    public void onStart() {}

    @Override
    public void onStop() {}

    @Override
    public void onDestroy() {}

    @Override
    public void onResourceReady(@NonNull Bitmap resource, @Nullable Transition<? super Bitmap> transition) {
        try {
            FileOutputStream out = new FileOutputStream(fileName);
            resource.compress(format, quality, out);
            out.flush();
            out.close();
            onFileSaved();
        } catch (IOException e) {
            e.printStackTrace();
            onSaveException(e);
        }
    }

    public void onFileSaved() {
        // do nothing, should be overriden
    }
    public void onSaveException(Exception e) {
        // do nothing, should be overriden
    }
}

Solution

  • Within the Android framework, there is a common pattern of creating an abstract FooAdapter class that implements all of the methods in a Foo interface with no-ops.

    For example, consider this class:

    public abstract class AnimatorListenerAdapter implements Animator.AnimatorListener,
            Animator.AnimatorPauseListener {
    
        @Override
        public void onAnimationCancel(Animator animation) { }
    
        @Override
        public void onAnimationEnd(Animator animation) { }
    
        @Override
        public void onAnimationRepeat(Animator animation) { }
    
        @Override
        public void onAnimationStart(Animator animation) { }
    
        @Override
        public void onAnimationPause(Animator animation) { }
    
        @Override
        public void onAnimationResume(Animator animation) { }
    }
    

    You could create the same thing for Glide:

    public abstract class TargetAdapter<T> implements Target<T> {
    
        @Override
        public void onLoadStarted(Drawable drawable) {}
    
        @Override
        public void onLoadFailed(Drawable drawable) {}
    
        @Override
        public void onLoadCleared(Drawable drawable) {}
    
        @Override
        public void getSize(SizeReadyCallback cb) {}
    
        @Override
        public void removeCallback(@NonNull SizeReadyCallback cb) {}
    
        @Override
        public void setRequest(@Nullable Request request) {}
    
        @Override
        public Request getRequest() {}
    
        @Override
        public void onResourceReady(@NonNull T resource, @Nullable Transition<? super T> transition) {}
    }
    

    Now, when you create your FileTarget class, you can declare that it extends TargetAdapter rather than implements Target, and only override the methods that you care about:

    public static class FileTarget<T extends Bitmap> extends TargetAdapter<Bitmap> {
        // ...
    
        @Override
        public void getSize(SizeReadyCallback cb) {
            cb.onSizeReady(width, height);
        }
    
        @Nullable
        @Override
        public Request getRequest() {
            return null;
        }
    
        @Override
        public void onResourceReady(@NonNull Bitmap resource, @Nullable Transition<? super Bitmap> transition) {
            try {
                FileOutputStream out = new FileOutputStream(fileName);
                resource.compress(format, quality, out);
                out.flush();
                out.close();
                onFileSaved();
            } catch (IOException e) {
                e.printStackTrace();
                onSaveException(e);
            }
        }
    
        // ...
    }