bumptech / glide

An image loading and caching library for Android focused on smooth scrolling
https://bumptech.github.io/glide/
Other
34.67k stars 6.12k forks source link

How to know when a Drawable is being released #4679

Open perracodex opened 3 years ago

perracodex commented 3 years ago

Glide Version: 4.12.0

Issue details / Repro steps / Use case background:

I am using a custom Drawable which implements the Animatable interface, so Glide will call the start/stop methods, which I need to initiate the drawable animation cycle. So whenever the ImageView gets cleared, or LifeCycle events get triggered, the drawable stop/start will also trigger as expected.

The issue I am having, is that I cannot find which interface to implement in the drawable that will be called when the ImageView gets cleared.

Next is the onLoadCleared from ImageViewTarget which calls animatable.stop() before clearing it with a placeholder or null. But the stop at this point doesn't tell the drawable if is being stopped because an onStop lifeCycle event or the onLoadCleared call.

  public void onLoadCleared(@Nullable Drawable placeholder) {
    super.onLoadCleared(placeholder);
    if (animatable != null) {
      animatable.stop();
    }
    setResourceInternal(null);
    setDrawable(placeholder);
  }

Is there any interface I can implement to the drawable to let it know is no longer needed? The use case is to know that the Drawable may no longer be used and can release some resources.

I have tried to wrap the Drawable with DrawableResource as I saw it has a recycle method, but it doesn't work because when creating the instance via the custom decoder the DataFetcher.loadData method never gets called if returning a DrawableResource .

If there is no applicable interface or solution, then a future request would be that ImageViewTarget class besides caching Animatable resources, also caches Closeable resources or any other type of interface that could be used to notify the current resource that is no longer needed.

Norte that I cannot extend GifDrawable as the custom drawable is very specific.

sjudd commented 3 years ago

The canonical way I think would be to have a custom ResourceDecoder that returns your Drawable return a specific Resource subclass: https://bumptech.github.io/glide/javadocs/4120/com/bumptech/glide/load/engine/Resource.html. That resource can then implement recycle() to tear itself down.

Is there a reason you're obtaining the Drawable in a DataFetcher instead of in a ResourceDecoder?

On Mon, Nov 1, 2021 at 2:32 PM perracolabs @.***> wrote:

Glide Version: 4.12.0

Issue details / Repro steps / Use case background:

I am using a custom Drawable which implements the Animatable interface, so Glide will call the start/stop methods, which I need to initiate the drawable animation cycle. So whenever the ImageView gets cleared, or LifeCycle events get triggered, the drawable stop/start will also trigger as expected.

The issue I am having, is that I cannot find which interface to implement in the drawable that will be called when the ImageView gets cleared.

Next is the onLoadCleared from ImageViewTarget which calls animatable.stop() before clearing it with a placeholder or null. But the stop at this point doesn't tell the drawable if is being stopped because an onStop lifeCycle event or the onLoadCleared call.

public void @.*** Drawable placeholder) { super.onLoadCleared(placeholder); if (animatable != null) { animatable.stop(); } setResourceInternal(null); setDrawable(placeholder); }

Is there any interface I can implement to the drawable to let it know is no longer needed? The use case is to know that the Drawable may no longer be used and can release some resources.

I have tried to wrap the Drawable with DrawableResource as I saw it has a recycle method, but it doesn't work because when creating the instance via the custom decoder the DataFetcher.loadData method never gets called if returning a DrawableResource .

If there is no applicable interface or solution, then a future request would be that ImageViewTarget class besides caching Animatable resources, also caches Closeable resources or any other type of interface that could be used to notify the current resource that is no longer needed.

Norte that I cannot extend GifDrawable as the custom drawable is very specific.

— You are receiving this because you are subscribed to this thread. Reply to this email directly, view it on GitHub https://github.com/bumptech/glide/issues/4679, or unsubscribe https://github.com/notifications/unsubscribe-auth/AAMNIS3FRSH4M5IHCL7O5T3UJ4BNHANCNFSM5HE6767Q . Triage notifications on the go with GitHub Mobile for iOS https://apps.apple.com/app/apple-store/id1477376905?ct=notification-email&mt=8&pt=524675 or Android https://play.google.com/store/apps/details?id=com.github.android&referrer=utm_campaign%3Dnotification-email%26utm_medium%3Demail%26utm_source%3Dgithub.

perracodex commented 3 years ago

Thanks for the prompt response. I wasn't aware I could do it in another way. I followed the documentation about how to create a custom model loader.

I couldn't find any documentation about how to implement a ResourceDecoder, so looking at the actual Glide's source code I made some assumptions and came with next code, unfortunately isn't working, Could you please let me know what would be the issue? Maybe this implementation is total a monstrosity, if so let me know if there is some documentation I can follow.

ResourceDecoder:

public final class TestDrawableResourceDecoder implements ResourceDecoder<String, TestDrawable> {
    @NonNull
    private static final String PREFIX = "anim:/";

    @NonNull
    private final Context context;

    public TestDrawableResourceDecoder(@NonNull final Context context) {
        this.context = context;
    }

    @Override
    public boolean handles(@NonNull final String source, @NonNull final Options options) throws IOException {
        return source.startsWith(TestDrawableResourceDecoder.PREFIX);
    }

    @NonNull
    public static String toModelUri(@NonNull final Uri uri) {
        return TestDrawableResourceDecoder.PREFIX + uri;
    }

    @Nullable
    @Override
    public Resource<TestDrawable> decode(@NonNull final String source, final int width, final int height,
                                               @NonNull final Options options) throws IOException {
        final TestDrawable drawable = TestDrawableFactory.newDrawable(this.context, source, width, height);
        return new TestDrawableResource(drawable);
    }
}

DrawableResource:

public final class TestDrawableResource extends DrawableResource<TestDrawable> {
    @SuppressWarnings("WeakerAccess")
    public TestDrawableResource(@NonNull final TestDrawable drawable) {
        super(drawable);
    }

    @NonNull
    @Override
    public Class<TestDrawable> getResourceClass() {
        return TestDrawable.class;
    }

    @Override
    public int getSize() {
        return this.drawable.getSize();
    }

    @Override
    public void recycle() {
        this.drawable.release();
    }
}

Registration in Glide's module:

...
registry.prepend(String.class, TestDrawable.class, new TestDrawableResourceDecoder(context));
...

Loading call:

    GlideApp.with(this.context)
            .load(TestDrawableResourceDecoder.toModelUri(record.uri))
            .diskCacheStrategy(DiskCacheStrategy.NONE)
            .into(imageView);
asthagarg2428 commented 2 years ago

I'm setting bitmap in my ImageView simply like this(Not using Glide in my project)- viewHolder.image.setImageBitmap(bitmap)

Unable to figure out when to recycle the bitmap, how glide handles this case internally?

stale[bot] commented 2 years ago

This issue has been automatically marked as stale because it has not had activity in the last seven days. It will be closed if no further activity occurs within the next seven days. Thank you for your contributions.