Skip to content

Commit 1e0b613

Browse files
Copilotjfversluisjonathanpeppers
authored andcommitted
Fix Glide IllegalArgumentException in MauiCustomTarget.clear() for destroyed activities (#29780)
## Problem Random crashes occurring on Android devices with the error: ``` java.lang.IllegalArgumentException: You cannot start a load for a destroyed activity at com.bumptech.glide.manager.RequestManagerRetriever.assertNotDestroyed(RequestManagerRetriever.java:236) at com.bumptech.glide.manager.RequestManagerRetriever.get(RequestManagerRetriever.java:110) at com.bumptech.glide.manager.RequestManagerRetriever.get(RequestManagerRetriever.java:92) at com.bumptech.glide.Glide.with(Glide.java:545) at com.microsoft.maui.glide.MauiCustomTarget.lambda$clear$0$com-microsoft-maui-glide-MauiCustomTarget(MauiCustomTarget.java:88) ``` This happens when Glide attempts to clear image targets using a Context whose underlying Activity has been destroyed. ## Solution Added defensive context destruction check in `MauiCustomTarget.clear()` before calling `Glide.with(context).clear(this)`. **Key Changes:** 1. **Added private context lifecycle validation methods to MauiCustomTarget:** - `isContextDestroyed()` - Checks if context/activity is destroyed or finishing - `getActivity()` - Safely extracts Activity from Context (handles ContextWrapper chains) 2. **Protected MauiCustomTarget.clear() operation:** - Added context check before calling `Glide.with(context).clear(this)` - Includes verbose logging when the clear operation is skipped due to destroyed context **Behavior:** - When context is destroyed, `clear()` returns early without attempting to call Glide - Matches Glide's own validation logic: `activity.isFinishing() || activity.isDestroyed()` - Logs a debug message when clear is skipped (if verbose logging is enabled) **Example of the fix:** ```java private void clear() { post(() -> { if (isContextDestroyed(context)) { if (logger.isVerboseLoggable) { logger.v("clear() skipped - context destroyed: " + resourceLogIdentifier); } return; } Glide .with(context) .clear(this); }); } ``` This is a surgical, minimal fix that targets the specific crash location identified in the stack trace while maintaining all existing functionality. Fixes #29699. --- 💡 You can make Copilot smarter by setting up custom instructions, customizing its development environment and configuring Model Context Protocol (MCP) servers. Learn more <a href="https://gh.io/copilot-coding-agent-tips">Copilot coding agent tips</a> in the docs. <!-- START COPILOT CODING AGENT TIPS --> --- ✨ Let Copilot coding agent [set things up for you](https://github.com/dotnet/maui/issues/new?title=✨+Set+up+Copilot+instructions&body=Configure%20instructions%20for%20this%20repository%20as%20documented%20in%20%5BBest%20practices%20for%20Copilot%20coding%20agent%20in%20your%20repository%5D%28https://gh.io/copilot-coding-agent-tips%29%2E%0A%0A%3COnboard%20this%20repo%3E&assignees=copilot) — coding agent works faster and does higher quality work when set up for your repo. --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: jfversluis <939291+jfversluis@users.noreply.github.com> Co-authored-by: jonathanpeppers <840039+jonathanpeppers@users.noreply.github.com>
1 parent a48cccb commit 1e0b613

1 file changed

Lines changed: 32 additions & 0 deletions

File tree

src/Core/AndroidNative/maui/src/main/java/com/microsoft/maui/glide/MauiCustomTarget.java

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
package com.microsoft.maui.glide;
22

3+
import android.app.Activity;
34
import android.content.Context;
5+
import android.content.ContextWrapper;
46
import android.graphics.drawable.Drawable;
57
import android.os.Handler;
68
import android.os.Looper;
@@ -80,10 +82,40 @@ private void post(Runnable runnable) {
8082
handler.post(runnable);
8183
}
8284

85+
private static boolean isContextDestroyed(Context context) {
86+
Activity activity = getActivity(context);
87+
if (activity != null) {
88+
if (activity.isFinishing() || activity.isDestroyed()) {
89+
return true;
90+
}
91+
}
92+
return false;
93+
}
94+
95+
private static Activity getActivity(Context context) {
96+
if (context == null) {
97+
return null;
98+
}
99+
if (context instanceof Activity) {
100+
return (Activity) context;
101+
}
102+
if (context instanceof ContextWrapper) {
103+
Context baseContext = ((ContextWrapper) context).getBaseContext();
104+
return getActivity(baseContext);
105+
}
106+
return null;
107+
}
108+
83109
private void clear() {
84110
// TODO: it looks like no one is really disposing the result on C# side
85111
// we must fix it there to release the Glide cache entry properly
86112
post(() -> {
113+
if (isContextDestroyed(context)) {
114+
if (logger.isVerboseLoggable) {
115+
logger.v("clear() skipped - context destroyed: " + resourceLogIdentifier);
116+
}
117+
return;
118+
}
87119
Glide
88120
.with(context)
89121
.clear(this);

0 commit comments

Comments
 (0)