Glide Version:compile 'com.github.bumptech.glide:glide:3.7.0'
Integration libraries:No
Device/Android Version:4.2.1,4.2.2,5.1
Issue details / Repro steps / Use case background: random crash(93 times in 12797 sessions) in my application which was due to Glide image loading,even did check for activity finish.
Glide load line / GlideModule (if any) / list Adapter code (if any):
private void setImageWithGlide(Context context, byte[] data) {
if (context == null || ((Activity) context).isFinishing())
return;
if (riv == null) {
riv = getRiv();
}
Glide.with(context).load(data).asBitmap().
listener(new RequestListener<byte[], Bitmap>() {
@Override
public boolean onException(Exception e, byte[] model, Target<Bitmap> target, boolean isFirstResource) {
return false;
}
@Override
public boolean onResourceReady(Bitmap resource, byte[] model, Target<Bitmap> target, boolean isFromMemoryCache, boolean isFirstResource) {
riv.setImageBitmap(resource);
fab.setImageDrawable(riv.getDrawable());
return true;
}
}).override(Constants.pxToDp(56), Constants.pxToDp(56)).
into(riv);
}
Layout XML:
Not relevant
Stack trace / LogCat:
IllegalArgumentException (@ContextMenuActivity:a:-1) {Crash Report Thread:main Exception:
java.lang.IllegalArgumentException: You cannot start a load for a destroyed activity
at com.bumptech.glide.d.l.a(Unknown Source)
at com.bumptech.glide.d.l.a(Unknown Source)
at com.bumptech.glide.g.b(Unknown Source)
at ...
Based on the description of onDestroy in the table below the image and lifecycle method listing:
onDestroy: The final call you receive before your activity is destroyed. This can happen either because the activity is finishing (someone called finish() on it, or because the system is temporarily destroying this instance of the activity to save space. You can distinguish between these two scenarios with the isFinishing() method.
isFinishing() == false does not mean that the activity is alive, because it'll return false for temporary destroys (e.g. rotation). Since Glide throws this exception when isDestroyed is true, you should be using the same to protect against latecoming callbacks. The best is if you can cancel the async task (in the opposite lifecycle method of where it was .execute()d) and check isCancelled() in onPostExecute, and don't do anything if it was cancelled.
Alternatively use the hacky workaround of caching Glide.with(context) into a variable earlier, so when you receive the byte[] data from the background into the UI you don't need to do with -> no exception.
@TWiStErRob Thanks to reply,
you mean to add
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1 && activity.isDestroyed()) this also
i.e. Do I need to check as
if (context == null || ((Activity) context).isFinishing() || (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1 && activity.isDestroyed()))
Yes, add that, and you can remove isFinishing as it doesn't give you the info you want.
But the key would be the cancelling of the task and checking is cancelled, the isDestroyed may not even be necessary.
Thanks Again,But In my case I cannot cancel AsyncTask.
Just curious: How come you can't cancel?
As I want to complete my Asynctask which is created for building cache for application start.
How to check if a Fragment was destroyed till this moment?
@TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1)
private static boolean isActivityDestroyed(Activity activity) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1
&& activity != null && activity.isDestroyed()) {
return true;
}
return false;
}
when you load image in Activity, please check like this. If the activity isDestroyed, stop load image by Glide, else load image by Glide
@Gaket
when you load image in a fragment , please get the Activity first like this, and then check whether the activity has destroyed
private static Activity getActivity(Context context) {
if (context == null) {
return null;
}
if (context instanceof Activity) {
return (Activity) context;
} else if (context instanceof ContextWrapper) {
return getActivity(((ContextWrapper) context).getBaseContext());
}
return null;
}