使用Glide在RelativeLayout图像中加载一个已销毁的活动时,您无法启动该加载。

82

我正在使用RelativeLayout来设置一张图片。为什么我没有使用ImageView呢?因为在RelativeLayout中,我正在设置图标。

我不知道Glide出了什么问题。我在下面发布了堆栈跟踪和相关代码:

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>
14个回答

157

用法:

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

替代写法:

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

希望这样解决了您的问题~

注意:如果决定使用applicationContext,请参考Glide image loading with application context


5
通过获取并使用ApplicationContext来解决这个问题:Glide.with(context.getApplicationContext()) .using(new FirebaseImageLoader()) .load(storageReference) .signature(new StringSignature(uri.toString())) .diskCacheStrategy(DiskCacheStrategy.ALL) .placeholder(placeHolder) .into(imageView); - dazza5000
11
这样做可以防止应用程序崩溃,但即使活动已被销毁,仍会使用资源来加载图像。 - JediBurrell
10
请参考 https://dev59.com/s1wZ5IYBdhLWcg3wBcIJ#32887693 ,了解为什么在Glide中使用应用程序上下文不是一个好主意。 - Cristan
3
在Android的上下文模型中,除非必要,否则使用应用程序上下文会完全破坏其目的。系统根据相关联的上下文决定释放或保留哪些资源,以执行或保留其周围的内容。已完成的Activity应该释放其资源。 - Adil Soomro
这个答案会修复你的崩溃问题...但性能会受到影响。请看下面的正确答案。 - Luke Needham
显示剩余4条评论

19

在受 GitHub线程的启发下,在加载任何图像之前我使用了这个

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

18

你可以通过手动检查上下文是否被销毁来确认;

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

这也可以表示为 Kotlin 扩展函数:

/**
 * 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
}

8
FragmentActivity不就是一个Activity吗? - Jintin

10

4

在使用Glide加载图片之前,请尝试执行以下操作。在我的情况下,mirefer是一个StorageReference,miimagen是一个ImageView。我通过以下方式解决了这个问题。希望能对你有所帮助。

if (!this.isFinishing ()) {
                // Load the image using Glide
                Glide.with(YourActivity.this)
                        .using(new FirebaseImageLoader())
                        .load(mirefer)
                        .into(miimagen);
            }

4

我几天前也遇到了相同的问题。我解决了这个问题,通过传递应用程序上下文内存代替当前类上下文内存。

也许这可以帮助你:

使用以下代码

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

如果你遇到了这个问题,请仔细阅读本文 "https://github.com/bumptech/glide/issues/1097"

问题概述:这是 Glide 库的一个问题。


如果它是片段,该怎么办? - Abhishek
如何在RecyclerView中实现呢? - Cyph3rCod3r
@Dr.aNdRO,使用RecyclerView适配器的构造函数进行传递。例如:Adapter adp = new Adapter(getApplicationContext(),list_of data),并在适配器中使用它。 - Peter
资源中正在使用上下文。为什么我要在那里传递应用程序上下文? - Cyph3rCod3r
请查看此链接:https://github.com/bumptech/glide/issues/1097,你会得到答案。 - Peter
显示剩余4条评论

1
使用具有正确生命周期的参数来设置 Glide。例如,在自定义视图中使用 Glide.with(this) 而不是 Glide.with(getContext())

这种方式为每个项目视图持有者初始化Glide,我认为对性能不利。 - user924

1

不要仅在适配器中使用来自活动的上下文作为context=this,而应该使用context.getApplicationContext();


1
你的回答可以通过提供更多支持信息来改进。请编辑以添加进一步的细节,例如引用或文档,以便他人可以确认你的答案是正确的。您可以在帮助中心找到有关如何编写良好答案的更多信息。 - Community

1

这里是一个 Kotlin 扩展,整合了上面几个答案 - this, thisthis

/**
 * 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
}

0
另一种方法是检查活动是否已被销毁,然后加载到UI元素中。
if (!newActivty.isDestroyed()){
   ...
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接