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() 是怎么实现的。


       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);
           }
   
  
  

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


       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");  //这里抛出了异常
               } 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"); //这里抛出了异常
               }
              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); //检查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"); //这里抛出了异常
               }
           }
          @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"); //这里抛出了异常
               }
              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);
               }
           }
          ...
       }
   
  
  

核心代码就在这里,我们看到也是有很多的重构方法,我们主要看这个方法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加载的工具类来解决这个问题比较好。


       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 加载 简单判空封装 防止异步加载数据时调用Glide 抛出异常
        * Created by Li_Xavier on 2017/6/20 0020.
        */
       public class GlideLoadUtils {
          private String TAG = "ImageLoader";
          /**
        * 借助内部类 实现线程安全的单例模式
        * 属于懒汉式单例,因为Java机制规定,内部类SingletonHolder只有在getInstance()
        * 方法第一次调用的时候才会被加载(实现了lazy),而且其加载过程是线程安全的。
        * 内部类加载的时候实例化一次instance。
        */
          public GlideLoadUtils() {
           }
          private static class GlideLoadUtilsHolder {
              private final static GlideLoadUtils INSTANCE = new GlideLoadUtils();
           }
          public static GlideLoadUtils getInstance() {
              return GlideLoadUtilsHolder.INSTANCE;
           }
          /**
        * Glide 加载 简单判空封装 防止异步加载数据时调用Glide 抛出异常
        *
        * @param context
        * @param url 加载图片的url地址 String
        * @param imageView 加载图片的ImageView 控件
        * @param default_image 图片展示错误的本地图片 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");
               }
           }
       }
   
  
  

上面是我简单写的一个小工具类
这只是我针对项目中碰到的异常做的简单分析,如果你想要详细的研究下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个月内不可修改。