glide
glide copied to clipboard
Multiple executions of the same failed target when backgrounding
Glide Version: 4.12.0
Integration libraries: n/a
Device/Android Version: Pixel 5 - API 30 emulator
Issue details / Repro steps / Use case background:
If an image fails to load (does not exist) then pausing and resuming the app triggers the load again
Glide load line / GlideModule
(if any) / list Adapter code (if any):
package com.example.myapplication;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.ImageView;
import com.bumptech.glide.Glide;
import com.bumptech.glide.RequestManager;
import com.bumptech.glide.request.target.CustomViewTarget;
import com.bumptech.glide.request.transition.Transition;
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button btn = findViewById(R.id.my_button);
ImageView img = findViewById(R.id.my_image);
btn.setOnClickListener(v -> {
RequestManager glide = Glide.with(img);
MyCustomViewTarget target = new MyCustomViewTarget(img, glide);
glide
.load("bad_file_name.png")
.into(target);
});
}
}
class MyCustomViewTarget extends CustomViewTarget<ImageView, Drawable> {
private final RequestManager requestManager;
private int counter;
public MyCustomViewTarget(@NonNull ImageView view, RequestManager requestManager) {
super(view);
this.requestManager = requestManager;
Log.e("MY_APP", "new MyCustomViewTarget");
}
@Override
protected void onResourceCleared(@Nullable Drawable placeholder) {
}
@Override
public void onLoadFailed(@Nullable Drawable errorDrawable) {
Log.e("MY_APP", "onLoadFailed: " + counter++);
}
@Override
public void onResourceReady(@NonNull Drawable resource, @Nullable Transition<? super Drawable> transition) {
Log.e("MY_APP", "onResourceReady");
this.view.setImageDrawable(resource);
}
}
Layout XML:
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<ImageView
android:layout_width="200dp"
android:layout_height="200dp"
android:id="@+id/my_image" />
<Button
android:layout_width="200dp"
android:layout_height="50dp"
android:text="Hello"
android:id="@+id/my_button" />
</LinearLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
https://user-images.githubusercontent.com/1096616/166216185-e2a846e1-ea54-4126-9fa7-6a7f573ef150.mp4
I think Bug/Feature is exactly the right way to describe this :).
As a general rule Glide's Targets do not complete once. One example where this is more clearly a feature is when Glide restarts failed requests when it thinks the app might have regained connectivity.
You can opt-out of the lifecycle by using the application context for Glide.with
, but that's not free because it removes other lifecycle integrations. It also doesn't remove the restart-on-connectivity-change behavior.
I could be convinced either way I guess. Restating failures for loads in normal Android Views seems pretty harmless. But when done for other frameworks or reasons it's easy to see why it's not what people expect.