- Recently, You cannot start a load for a destroyed activity was encountered when using Glide to load network pictures while working on a project; Scenario Description: Click to enter an activity to request the network. After the successful request, use Glide to load the network image according to the image URL returned by the server. This error will be reported when you click to enter the activity and exit the activity during the network loading process If you have time today, just study this problem and take a note. I hope it can bring some help to the little partners who also encounter this problem
Let's first look at the simple call of Glide:
Glide.with(context).load(imageUrl).into(imageView);
According to the abnormal prompt, we can determine that the problem should be glide Context in with (context) Let's go to the source code and take a look at glide How with() is implemented.
public static RequestManager with(Context context) { RequestManagerRetriever retriever = RequestManagerRetriever.get(); return retriever.get(context); } public static RequestManager with(Activity activity) { RequestManagerRetriever retriever = RequestManagerRetriever.get(); return retriever.get(activity); } public static RequestManager with(FragmentActivity activity) { RequestManagerRetriever retriever = RequestManagerRetriever.get(); return retriever.get(activity); } @TargetApi(Build.VERSION_CODES.HONEYCOMB) public static RequestManager with(android.app.Fragment fragment) { RequestManagerRetriever retriever = RequestManagerRetriever.get(); return retriever.get(fragment); } public static RequestManager with(Fragment fragment) { RequestManagerRetriever retriever = RequestManagerRetriever.get(); return retriever.get(fragment); }
You can see that there are many refactoring methods, but they will eventually return a retriever get(); We continue to the retriever Get (), we will see the RequestManagerRetriever class.
public class RequestManagerRetriever implements Handler.Callback { ... public RequestManager get(Context context) { if (context == null) { throw new IllegalArgumentException("You cannot start a load on a null Context"); //An exception is thrown here } else if (Util.isOnMainThread() && !(context instanceof Application)) { if (context instanceof FragmentActivity) { return get((FragmentActivity) context); } else if (context instanceof Activity) { return get((Activity) context); } else if (context instanceof ContextWrapper) { return get(((ContextWrapper) context).getBaseContext()); } } return getApplicationManager(context); } public RequestManager get(FragmentActivity activity) { if (Util.isOnBackgroundThread()) { return get(activity.getApplicationContext()); } else { assertNotDestroyed(activity); FragmentManager fm = activity.getSupportFragmentManager(); return supportFragmentGet(activity, fm); } } public RequestManager get(Fragment fragment) { if (fragment.getActivity() == null) { throw new IllegalArgumentException("You cannot start a load on a fragment before it is attached"); //An exception is thrown here } if (Util.isOnBackgroundThread()) { return get(fragment.getActivity().getApplicationContext()); } else { FragmentManager fm = fragment.getChildFragmentManager(); return supportFragmentGet(fragment.getActivity(), fm); } } @TargetApi(Build.VERSION_CODES.HONEYCOMB) public RequestManager get(Activity activity) { if (Util.isOnBackgroundThread() || Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB) { return get(activity.getApplicationContext()); } else { assertNotDestroyed(activity); //Method for checking activity android.app.FragmentManager fm = activity.getFragmentManager(); return fragmentGet(activity, fm); } } @TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1) private static void assertNotDestroyed(Activity activity) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1 && activity.isDestroyed()) { throw new IllegalArgumentException("You cannot start a load for a destroyed activity"); //An exception is thrown here } } @TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1) public RequestManager get(android.app.Fragment fragment) { if (fragment.getActivity() == null) { throw new IllegalArgumentException("You cannot start a load on a fragment before it is attached"); //An exception is thrown here } if (Util.isOnBackgroundThread() || Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR1) { return get(fragment.getActivity().getApplicationContext()); } else { android.app.FragmentManager fm = fragment.getChildFragmentManager(); return fragmentGet(fragment.getActivity(), fm); } } ... }
The core code is here. We can see that there are many refactoring methods. We mainly look at this method, assertnotdestroyed (activity)

All right, find the place where Glide threw the exception!
That is, when activity When isdestroyed() is true
There are also several other exceptions: You cannot start a load on a fragment before it is attached
You cannot start a load on a null Context
In the final analysis, it is because we have passed in a destroyed Activity or an empty context, and the Activity mounted by fragment is empty
Recall that the scenario used is called Glide after the success of the networking request when it is executed to Glide.. with(); Method, the current Activity has been destroyed, which leads to this problem.
We try not to use Glide to load pictures in non main threads, which will easily lead to throwing exceptions such as You cannot start a load for a destroyed activity. If there is a need, one solution is to directly pass in the Application object, so that there will be no problem. However, using the Application object will lead to a longer life cycle of Glide loading pictures, When the Activity has been destroyed, it continues to load pictures, which will waste a lot of resources, so we'd better simply encapsulate a Glide loaded tool class to solve this problem.
import android.annotation.TargetApi; import android.app.Activity; import android.content.Context; import android.os.Build; import android.support.v4.app.Fragment; import android.util.Log; import android.widget.ImageView; import com.bumptech.glide.Glide; /** * Glide Loading simple null encapsulation prevents calling Glide to throw an exception when loading data asynchronously * Created by Li_Xavier on 2017/6/20 0020. */ public class GlideLoadUtils { private String TAG = "ImageLoader"; /** * Implementation of thread safe singleton mode with internal classes * This is a lazy singleton, because the Java mechanism stipulates that the inner class SingletonHolder is only in getInstance() * The method is loaded only when it is called for the first time (lazy is implemented), and its loading process is thread safe. * instance is instantiated when the internal class is loaded. */ public GlideLoadUtils() { } private static class GlideLoadUtilsHolder { private final static GlideLoadUtils INSTANCE = new GlideLoadUtils(); } public static GlideLoadUtils getInstance() { return GlideLoadUtilsHolder.INSTANCE; } /** * Glide Loading simple null encapsulation prevents calling Glide to throw an exception when loading data asynchronously * * @param context * @param url url address of the loaded picture String * @param imageView Load the ImageView control for the picture * @param default_image The picture shows the wrong local picture id */ public void glideLoad(Context context, String url, ImageView imageView, int default_image) { if (context != null) { Glide.with(context).load(url).centerCrop().error(default_image).crossFade ().into(imageView); } else { Log.i(TAG, "Picture loading failed,context is null"); } } @TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1) public void glideLoad(Activity activity, String url, ImageView imageView, int default_image) { if (!activity.isDestroyed()) { Glide.with(activity).load(url).centerCrop().error(default_image).crossFade ().into(imageView); } else { Log.i(TAG, "Picture loading failed,activity is Destroyed"); } } public void glideLoad(Fragment fragment, String url, ImageView imageView, int default_image) { if (fragment != null && fragment.getActivity() != null) { Glide.with(fragment).load(url).centerCrop().error(default_image).crossFade ().into(imageView); } else { Log.i(TAG, "Picture loading failed,fragment is null"); } } public void glideLoad(android.app.Fragment fragment, String url, ImageView imageView, int default_image) { if (fragment != null && fragment.getActivity() != null) { Glide.with(fragment).load(url).centerCrop().error(default_image).crossFade ().into(imageView); } else { Log.i(TAG, "Picture loading failed,android.app.Fragment is null"); } } }
The above is a small tool class I simply wrote This is just a simple analysis of the exceptions encountered in the project. If you want to study the source code of Glide in detail, please refer to Guo Lin dada's blog: http://blog.csdn.net/guolin_blog/article/details/53939176