82

I am using relativelayout to set an image.Why I hadn't using imageview means, inside relativelayout image, I am setting icons.

I dont know what is the issue exactly in glide.I have posted the stacktrace and relevant code below:

Logcat:

 FATAL EXCEPTION: main
   Process: com.app.steve, PID: 15928 
 java.lang.IllegalArgumentException: You cannot start a load for a destroyed activity
   at com.bumptech.glide.manager.RequestManagerRetriever.assertNotDestroyed(RequestManagerRetriever.java:134)
   at com.bumptech.glide.manager.RequestManagerRetriever.get(RequestManagerRetriever.java:102)
   at com.bumptech.glide.Glide.with(Glide.java:644)
                                                                    at com.app.steve.TabMorePagesDetailActivity$allPageDetails.onPostExecute(TabMorePagesDetailActivity.java:1050)
     at com.app.steve.TabMorePagesDetailActivity$allPageDetails.onPostExecute(TabMorePagesDetailActivity.java:885)
    at android.os.AsyncTask.finish(AsyncTask.java:632)
    at android.os.AsyncTask.access$600(AsyncTask.java:177)
   at android.os.AsyncTask$InternalHandler.handleMessage(AsyncTask.java:645)
    at android.os.Handler.dispatchMessage(Handler.java:102)
    at android.os.Looper.loop(Looper.java:135)
    at android.app.ActivityThread.main(ActivityThread.java:5221)
   at java.lang.reflect.Method.invoke(Native Method)
    at java.lang.reflect.Method.invoke(Method.java:372)
    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:899)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:694)

TabMorePagesDetailActivity.java:

RelativeLayout rlPageCoverImg;

rlPageCoverImg = (RelativeLayout)findViewById(R.id.rl_club_cover_img);

@Override
        protected void onPostExecute(String response) {
            super.onPostExecute(response);

            dialog.dismiss();
        ............

    String coverIMGurl = cover_avatar_obj.getString("url");

    Log.e("ImgURL", coverIMGurl);

 Glide.with(TabMorePagesDetailActivity.this).load(coverIMGurl).asBitmap().signature(new StringSignature(String.valueOf(System.currentTimeMillis())))
                                        .into(new SimpleTarget<Bitmap>(500, 500) {

    @Override
    public void onResourceReady(Bitmap resource, GlideAnimation<? super Bitmap> glideAnimation) {
    Drawable drawable = new BitmapDrawable(getResources(), resource);
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
                                            rlPageCoverImg.setBackground(drawable);
    }
    }
    });

    }else {

    rlPageCoverImg.setBackgroundResource(R.drawable.bg_golive);

    }



    @Override
 protected void onDestroy()
 {
    super.onDestroy();
    Glide.clear(rlPageCoverImg);

 }

layout.xml:

 <RelativeLayout
            android:id="@+id/rl_club_cover_img"
            android:layout_width="match_parent"
            android:layout_height="200dp"
            android:background="@drawable/cancel_image" >

  // Inside this relativelayout image, I'm using buttons and icons


 </RelativeLayout>
Stephen
  • 9,899
  • 16
  • 90
  • 137

14 Answers14

156

Use:

Glide.with(getApplicationContext()).load(...)

Instead of:

Glide.with(TabMorePagesDetailActivity.this).load(...)

Hope it will solve your problem~

BEWARE: See Glide image loading with application context if you decide to use applicationContext

Ferdous Ahamed
  • 21,438
  • 5
  • 52
  • 61
  • 4
    Also fixed this by getting and using the ApplicationContext: Glide.with(context.getApplicationContext()) .using(new FirebaseImageLoader()) .load(storageReference) .signature(new StringSignature(uri.toString())) .diskCacheStrategy(DiskCacheStrategy.ALL) .placeholder(placeHolder) .into(imageView); – dazza5000 Mar 26 '17 at 00:53
  • 11
    This will stop it from crashing, but will still use the resources to load the image even if the activity has been destroyed. – JediBurrell Sep 16 '18 at 08:19
  • 10
    See https://stackoverflow.com/a/32887693/389649 for why using your application context in Glide isn't a good idea. – Cristan Feb 11 '19 at 16:18
  • I have tried to use your solution but my app is crashing – Rizki Oktavia Ningrum Jan 05 '20 at 13:54
  • 3
    Using application context (unless required) totally destroys the purpose of Android's context model. System decides which resource to release or to keep in memory, to execute or keep around based on the affiliated context. Finished Activity should release its resources. – Adil Soomro May 05 '20 at 01:58
  • This answer will fix your crash... at the expense of performance. See below for the proper answers – Luke Needham May 08 '20 at 15:18
  • it's not a solution! – user924 Dec 22 '20 at 12:09
  • Not a good solution. You should use https://stackoverflow.com/a/60368532/5695458 – babaliaris Jun 21 '21 at 11:22
  • You would start getting a lot of outOfMemory errors. Be careful using this solution. You would get rid of the crash, though the in-memory cache would be always alive until your appcontext is alive. Glide is clearing it's mem-cache when context dies. so identify in which particular container your data should live and choose activity, fragment or whatever context you need. – Jenya Kirmiza Jul 11 '21 at 18:36
19

Inspired from a GitHub thread, I am using this before loading any image

final Context  context = getApplication().getApplicationContext();

if (isValidContextForGlide(context)){
                // Load image via Glide lib using context
               
  }

 public static boolean isValidContextForGlide(final Context context) {
    if (context == null) {
        return false;
    }
    if (context instanceof Activity) {
        final Activity activity = (Activity) context;
        if (activity.isDestroyed() || activity.isFinishing()) {
            return false;
        }
    }
    return true;
}
Ankit Mishra
  • 530
  • 8
  • 16
Sethuraman Srinivasan
  • 1,528
  • 1
  • 20
  • 34
18

You can simply check the context is destroyed or not manually as;

if (context == null) {
    return
} else if (context !is Application) {
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
        if (context is FragmentActivity) {
            if ((context as FragmentActivity).isDestroyed) {
                return
            }
        } else if (context is Activity) {
            if ((context as Activity).isDestroyed) {
                return
            }
        }
    }
}

This can also be represented as a Kotlin extension function:

/**
 * Return true if this [Context] is available.
 * Availability is defined as the following:
 * + [Context] is not null
 * + [Context] is not destroyed (tested with [FragmentActivity.isDestroyed] or [Activity.isDestroyed])
 */
fun Context?.isAvailable(): Boolean {
    if (this == null) {
        return false
    } else if (this !is Application) {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
            if (this is FragmentActivity) {
                return !this.isDestroyed
            } else if (this is Activity) {
                return !this.isDestroyed
            }
        }
    }
    return true
}
Knossos
  • 15,802
  • 10
  • 54
  • 91
DiRiNoiD
  • 1,281
  • 2
  • 18
  • 24
10

Please do not use Glide.with(getApplicationContext()) unless you really need to, for reasons discussed here: Glide image loading with application context

The correct answer is outlined here: https://github.com/bumptech/glide/issues/1484#issuecomment-365625087

In Kotlin, that can be written as an extension function:

fun Context.isValidGlideContext() = this !is Activity || (!this.isDestroyed && !this.isFinishing)
Luke Needham
  • 3,373
  • 1
  • 24
  • 41
4

I have got the same issue before few days.I have solved this to passing the Application context memory behalf of current Class context memory.

May be it will help you :-

use this code

 Glide.with(getApplicationContext())
           .load(coverIMGurl)
           .asBitmap()
           .signature(new StringSignature(String.valueOf(System.currentTimeMillis())))
                                    .into(new SimpleTarget<Bitmap>(500, 500) {....}

Even you are getting this issue then read this article carefully "https://github.com/bumptech/glide/issues/1097"

overview for this issue : This is an issue of Glide library.

Peter
  • 587
  • 6
  • 16
  • what to do if it is fragment..? – Abhishek Jan 17 '18 at 05:42
  • getActivity().getApplicationContext(); @Abhishek – Shadow Feb 26 '18 at 10:01
  • Return the context of the single, global Application object of the current process. This generally should only be used if you need a Context whose lifecycle is separate from the current context, that is tied to the lifetime of the process rather than the current component @Abhishek In case of fragment you need to use getActivity().getApplicationContext() – Peter Aug 21 '18 at 13:56
  • How to do it in recyclerview then? – Cyph3rCod3r Sep 03 '18 at 12:10
  • @Dr.aNdRO pass with constructor of recyclerview adapter for example Adapter adp = new Adapter(getApplicationContext(),list_of data), and use that in adapter. – Peter Sep 03 '18 at 12:17
  • that context is getting used in resources. Why would I pass application Context there? – Cyph3rCod3r Sep 03 '18 at 12:59
  • "https://github.com/bumptech/glide/issues/1097 check this one you will get your answer. – Peter Sep 03 '18 at 13:03
  • Guys using application context is not a good idea here. In case your activity is destroyed it still want to load the image. This is not the right way – Cyph3rCod3r Feb 27 '20 at 11:36
  • it's not a solution! – user924 Dec 22 '20 at 12:09
4

Try this before load your image with Glide, in my case mirefer is a StorageReference, miimagen is a ImageView. I solved this problem, with this. I hope it could help you.

if (!this.isFinishing ()) {
                // Load the image using Glide
                Glide.with(YourActivity.this)
                        .using(new FirebaseImageLoader())
                        .load(mirefer)
                        .into(miimagen);
            }
Liliana J
  • 549
  • 1
  • 5
  • 13
1

Setup Glide with a parameter which has the correct lifecycle. For example: use Glide.with(this) instead of Glide.with(getContext()) in a custom view.

Cristan
  • 12,083
  • 7
  • 65
  • 69
1

Here is a Kotlin extension that puts together a few answers above - this, this, and this:

/**
 * Returns true when [Context] is unavailable or is about to become unavailable
 */
fun Context?.isDoomed(): Boolean = when (this) {
    null -> true
    is Application -> false
    is Activity -> (this.isDestroyed or this.isFinishing)
    else -> false
}
Guido
  • 109
  • 2
  • 9
1

Don't just use context in adapter which you take from activity as context=this rather use context.getApplicationContext();

  • 1
    Your answer could be improved with additional supporting information. Please [edit] to add further details, such as citations or documentation, so that others can confirm that your answer is correct. You can find more information on how to write good answers [in the help center](/help/how-to-ask). – Community Sep 13 '21 at 10:36
0

the other way is to check if the activity is destroyed or not, then load into UI element.

if (!newActivty.isDestroyed()){
   ...
}
Gv Ravi
  • 333
  • 2
  • 5
0

hi in view model for frament The activity context is kept even when you press the back button and exit the program. And go back to the program, you do not need to re-value the context because the context is static

@Override
    public void onBindViewHolder(@NonNull final viewholder viewholder, final int i) {
        final Model_Post model_post = list.get(i);
        Log.e(TAG, "onBindViewHolder: "+model_post.getImageurl());

        Glide.with(MainActivity.activity)
                .load(Uri.parse(model_post.getImageurl()))
                .diskCacheStrategy(DiskCacheStrategy.ALL)
                .into(viewholder.itemsPostBinding.imgvItempost);

    }

You must do this in main activity :

public static AppCompatActivity activity;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    activity = MainActivity.this;
}
  • 2
    No no no. You should never store activity as a static variable. This will cause memory leaks. https://android-developers.googleblog.com/2009/01/avoiding-memory-leaks.html – Saurabh Sep 05 '20 at 09:04
  • So how do I set the context in the adapter to use glide? My glide is in an adapter in recyclerview – ali moradi Sep 10 '20 at 07:33
0

Pls use Glide.with(holder.itemView.getContext()).load....... It has solved my issue ref https://github.com/bumptech/glide/issues/2690

Bineesh Kumar
  • 123
  • 10
0

Just use this helper class:

/**
 * @Lukas Niessen
 */
public class GlideUsus {

    public static final String TAG = "GlideUsus";

    public interface Interface {
        void doIfValidContext(RequestManager requestManager);
    }

    public static void execute(Context context, GlideUsus.Interface action) {
        if (isValidContextForGlide(context)) {
            action.doIfValidContext(Glide.with(context));
        } else {
            // nothing
            Log.v(TAG, "Loading image failed");
        }
    }

    public static boolean isValidContextForGlide(final Context context) {
        if (context == null) {
            return false;
        }
        if (context instanceof Activity) {
            final Activity activity = (Activity) context;
            if (activity.isDestroyed() || activity.isFinishing()) {
                return false;
            }
        }
        return true;
    }
}

Usage:

GlideUsus.execute(mContext, (a -> a.load(uri).into(image)));
mathematics-and-caffeine
  • 1,664
  • 2
  • 15
  • 19
-2

In activity I use Glide.with(getApplicatonContext()) and in adapter I use Glide.with(myContext.getApplicatonContext())

//It works for me fine.

//for adapter

Context myContext;

//also initilize in `oncreateViewHolder`

@Override
    public MessagesHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.custom_messages_layout, parent, false);
        myContext = parent.getContext();
        return new MessagesHolder(view);
    }
Biscuit
  • 4,840
  • 4
  • 26
  • 54
  • You shouldn't use application context with `Glide.with`, here is the explanation: https://stackoverflow.com/a/32887693/6074224 – Biscuit Oct 26 '20 at 09:57