Glide类似You cannot start a load for a destroyed activity异常简单分析

举报
程思扬 发表于 2022/01/13 23:32:59 2022/01/13
【摘要】 最近在做项目时,使用Glide加载网络图片时,碰到了 You cannot start a load for a destroyed activity 这个异常; 场景描述:点击进入一个Activity 当中请求网络 请求成功后 根据服务器返回的图片URL使用Glide来加载网络图片 ,当点击进入activity...
  • 最近在做项目时,使用Glide加载网络图片时,碰到了 You cannot start a load for a destroyed activity 这个异常;

    场景描述:点击进入一个Activity 当中请求网络 请求成功后 根据服务器返回的图片URL使用Glide来加载网络图片 ,当点击进入activity 加载网络过程中 退出activity 会报此错

    今天有时间就索性研究下这个问题,就做个笔记,也希望能给同样碰到这个问题的小伙伴带来点帮助

先看下Glide的简单调用:

Glide.with(context).load(imageUrl).into(imageView);

根据异常的提示,我们可以确定问题应该是出在了Glide.with(context) 中的context
我们点到源码中看一下 Glide.with() 是怎么实现的。


   
  1. public static RequestManager with(Context context) {
  2. RequestManagerRetriever retriever = RequestManagerRetriever.get();
  3. return retriever.get(context);
  4. }
  5. public static RequestManager with(Activity activity) {
  6. RequestManagerRetriever retriever = RequestManagerRetriever.get();
  7. return retriever.get(activity);
  8. }
  9. public static RequestManager with(FragmentActivity activity) {
  10. RequestManagerRetriever retriever = RequestManagerRetriever.get();
  11. return retriever.get(activity);
  12. }
  13. @TargetApi(Build.VERSION_CODES.HONEYCOMB)
  14. public static RequestManager with(android.app.Fragment fragment) {
  15. RequestManagerRetriever retriever = RequestManagerRetriever.get();
  16. return retriever.get(fragment);
  17. }
  18. public static RequestManager with(Fragment fragment) {
  19. RequestManagerRetriever retriever = RequestManagerRetriever.get();
  20. return retriever.get(fragment);
  21. }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25

可以看到这里有很多的重构的方法,但是最终都会返回一个retriever.get(); 我们继续到retriever.get()里面去,我们会看到 RequestManagerRetriever 类。


   
  1. public class RequestManagerRetriever implements Handler.Callback {
  2. ...
  3. public RequestManager get(Context context) {
  4. if (context == null) {
  5. throw new IllegalArgumentException("You cannot start a load on a null Context"); //这里抛出了异常
  6. } else if (Util.isOnMainThread() && !(context instanceof Application)) {
  7. if (context instanceof FragmentActivity) {
  8. return get((FragmentActivity) context);
  9. } else if (context instanceof Activity) {
  10. return get((Activity) context);
  11. } else if (context instanceof ContextWrapper) {
  12. return get(((ContextWrapper) context).getBaseContext());
  13. }
  14. }
  15. return getApplicationManager(context);
  16. }
  17. public RequestManager get(FragmentActivity activity) {
  18. if (Util.isOnBackgroundThread()) {
  19. return get(activity.getApplicationContext());
  20. } else {
  21. assertNotDestroyed(activity);
  22. FragmentManager fm = activity.getSupportFragmentManager();
  23. return supportFragmentGet(activity, fm);
  24. }
  25. }
  26. public RequestManager get(Fragment fragment) {
  27. if (fragment.getActivity() == null) {
  28. throw new IllegalArgumentException("You cannot start a load on a fragment before it is attached"); //这里抛出了异常
  29. }
  30. if (Util.isOnBackgroundThread()) {
  31. return get(fragment.getActivity().getApplicationContext());
  32. } else {
  33. FragmentManager fm = fragment.getChildFragmentManager();
  34. return supportFragmentGet(fragment.getActivity(), fm);
  35. }
  36. }
  37. @TargetApi(Build.VERSION_CODES.HONEYCOMB)
  38. public RequestManager get(Activity activity) {
  39. if (Util.isOnBackgroundThread() || Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB) {
  40. return get(activity.getApplicationContext());
  41. } else {
  42. assertNotDestroyed(activity); //检查activity的方法
  43. android.app.FragmentManager fm = activity.getFragmentManager();
  44. return fragmentGet(activity, fm);
  45. }
  46. }
  47. @TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1)
  48. private static void assertNotDestroyed(Activity activity) {
  49. if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1 && activity.isDestroyed()) {
  50. throw new IllegalArgumentException("You cannot start a load for a destroyed activity"); //这里抛出了异常
  51. }
  52. }
  53. @TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1)
  54. public RequestManager get(android.app.Fragment fragment) {
  55. if (fragment.getActivity() == null) {
  56. throw new IllegalArgumentException("You cannot start a load on a fragment before it is attached"); //这里抛出了异常
  57. }
  58. if (Util.isOnBackgroundThread() || Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR1) {
  59. return get(fragment.getActivity().getApplicationContext());
  60. } else {
  61. android.app.FragmentManager fm = fragment.getChildFragmentManager();
  62. return fragmentGet(fragment.getActivity(), fm);
  63. }
  64. }
  65. ...
  66. }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76

核心代码就在这里,我们看到也是有很多的重构方法,我们主要看这个方法assertNotDestroyed(Activity activity)

这里写图片描述

好了 找到Glide 抛出异常的地方了!

也就是当 activity.isDestroyed()为true的时候

同样的还有另外几个异常:
You cannot start a load on a fragment before it is attached

You cannot start a load on a null Context

归根结底都是因为我们传入了一个已经销毁的Activity或者是一个空的Context ,Fragment 挂载的Activity为空导致的

回顾使用的场景,是在联网请求成功之后调用的Glide 当执行到Glide.with();方法时,当前的Activity已经销毁了,所以才导致的这个问题。

我们尽量不要再非主线程里面使用Glide加载图片,这样容易导致抛出如You cannot start a load for a destroyed activity的异常,如果有需求的话,有一种解决方案是直接传入Application对象,这样就不会有这个问题了,但是使用Application对象会导致Glide加载图片的生命周期变长,当Activity已经销毁时,还在继续的加载图片,这样做会浪费很多的资源,所以我们还是简单的封装一个Glide加载的工具类来解决这个问题比较好。


   
  1. import android.annotation.TargetApi;
  2. import android.app.Activity;
  3. import android.content.Context;
  4. import android.os.Build;
  5. import android.support.v4.app.Fragment;
  6. import android.util.Log;
  7. import android.widget.ImageView;
  8. import com.bumptech.glide.Glide;
  9. /**
  10. * Glide 加载 简单判空封装 防止异步加载数据时调用Glide 抛出异常
  11. * Created by Li_Xavier on 2017/6/20 0020.
  12. */
  13. public class GlideLoadUtils {
  14. private String TAG = "ImageLoader";
  15. /**
  16. * 借助内部类 实现线程安全的单例模式
  17. * 属于懒汉式单例,因为Java机制规定,内部类SingletonHolder只有在getInstance()
  18. * 方法第一次调用的时候才会被加载(实现了lazy),而且其加载过程是线程安全的。
  19. * 内部类加载的时候实例化一次instance。
  20. */
  21. public GlideLoadUtils() {
  22. }
  23. private static class GlideLoadUtilsHolder {
  24. private final static GlideLoadUtils INSTANCE = new GlideLoadUtils();
  25. }
  26. public static GlideLoadUtils getInstance() {
  27. return GlideLoadUtilsHolder.INSTANCE;
  28. }
  29. /**
  30. * Glide 加载 简单判空封装 防止异步加载数据时调用Glide 抛出异常
  31. *
  32. * @param context
  33. * @param url 加载图片的url地址 String
  34. * @param imageView 加载图片的ImageView 控件
  35. * @param default_image 图片展示错误的本地图片 id
  36. */
  37. public void glideLoad(Context context, String url, ImageView imageView, int default_image) {
  38. if (context != null) {
  39. Glide.with(context).load(url).centerCrop().error(default_image).crossFade
  40. ().into(imageView);
  41. } else {
  42. Log.i(TAG, "Picture loading failed,context is null");
  43. }
  44. }
  45. @TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1)
  46. public void glideLoad(Activity activity, String url, ImageView imageView, int default_image) {
  47. if (!activity.isDestroyed()) {
  48. Glide.with(activity).load(url).centerCrop().error(default_image).crossFade
  49. ().into(imageView);
  50. } else {
  51. Log.i(TAG, "Picture loading failed,activity is Destroyed");
  52. }
  53. }
  54. public void glideLoad(Fragment fragment, String url, ImageView imageView, int default_image) {
  55. if (fragment != null && fragment.getActivity() != null) {
  56. Glide.with(fragment).load(url).centerCrop().error(default_image).crossFade
  57. ().into(imageView);
  58. } else {
  59. Log.i(TAG, "Picture loading failed,fragment is null");
  60. }
  61. }
  62. public void glideLoad(android.app.Fragment fragment, String url, ImageView imageView, int default_image) {
  63. if (fragment != null && fragment.getActivity() != null) {
  64. Glide.with(fragment).load(url).centerCrop().error(default_image).crossFade
  65. ().into(imageView);
  66. } else {
  67. Log.i(TAG, "Picture loading failed,android.app.Fragment is null");
  68. }
  69. }
  70. }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79

上面是我简单写的一个小工具类
这只是我针对项目中碰到的异常做的简单分析,如果你想要详细的研究下Glide的源码 请参考郭霖大大的博客:http://blog.csdn.net/guolin_blog/article/details/53939176

文章来源: chengsy.blog.csdn.net,作者:程思扬,版权归原作者所有,如需转载,请联系作者。

原文链接:chengsy.blog.csdn.net/article/details/79732044

【版权声明】本文为华为云社区用户转载文章,如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。