diff --git a/.gitignore b/.gitignore
index 598def77e641..daafde085962 100644
--- a/.gitignore
+++ b/.gitignore
@@ -388,3 +388,6 @@ temp
# TypeScript source map files (generated artifacts)
# Note: CSS map files in templates (e.g., bootstrap) are intentionally tracked
*.js.map
+
+# Gradle build reports
+src/Core/AndroidNative/build/reports/
diff --git a/src/Core/AndroidNative/build/reports/problems/problems-report.html b/src/Core/AndroidNative/build/reports/problems/problems-report.html
deleted file mode 100644
index 28c86c49448d..000000000000
--- a/src/Core/AndroidNative/build/reports/problems/problems-report.html
+++ /dev/null
@@ -1,663 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
- Gradle Configuration Cache
-
-
-
-
-
-
- Loading...
-
-
-
-
-
-
-
diff --git a/src/Core/AndroidNative/maui/src/main/java/com/microsoft/maui/PlatformInterop.java b/src/Core/AndroidNative/maui/src/main/java/com/microsoft/maui/PlatformInterop.java
index 10f724424e45..2601e0b5f351 100644
--- a/src/Core/AndroidNative/maui/src/main/java/com/microsoft/maui/PlatformInterop.java
+++ b/src/Core/AndroidNative/maui/src/main/java/com/microsoft/maui/PlatformInterop.java
@@ -2,6 +2,7 @@
import android.app.Activity;
import android.content.Context;
+import android.content.ContextWrapper;
import android.content.res.ColorStateList;
import android.graphics.BlendMode;
import android.graphics.BlendModeColorFilter;
@@ -363,6 +364,10 @@ public static void loadImageFromFont(ImageView imageView, @ColorInt int color, S
}
public static void loadImageFromFile(Context context, String file, ImageLoaderCallback callback) {
+ if (isContextDestroyed(context)) {
+ callback.onComplete(false, null, null);
+ return;
+ }
RequestBuilder builder = Glide
.with(context)
.load(file);
@@ -370,6 +375,10 @@ public static void loadImageFromFile(Context context, String file, ImageLoaderCa
}
public static void loadImageFromUri(Context context, String uri, boolean cachingEnabled, ImageLoaderCallback callback) {
+ if (isContextDestroyed(context)) {
+ callback.onComplete(false, null, null);
+ return;
+ }
Uri androidUri = Uri.parse(uri);
if (androidUri == null) {
callback.onComplete(false, null, null);
@@ -382,6 +391,10 @@ public static void loadImageFromUri(Context context, String uri, boolean caching
}
public static void loadImageFromStream(Context context, InputStream inputStream, ImageLoaderCallback callback) {
+ if (isContextDestroyed(context)) {
+ callback.onComplete(false, null, null);
+ return;
+ }
RequestBuilder builder = Glide
.with(context)
.load(inputStream);
@@ -389,6 +402,10 @@ public static void loadImageFromStream(Context context, InputStream inputStream,
}
public static void loadImageFromFont(Context context, @ColorInt int color, String glyph, Typeface typeface, float textSize, ImageLoaderCallback callback) {
+ if (isContextDestroyed(context)) {
+ callback.onComplete(false, null, null);
+ return;
+ }
FontModel fontModel = new FontModel(color, glyph, textSize, typeface);
RequestBuilder builder = Glide
.with(context)
@@ -704,4 +721,39 @@ public static boolean isImageViewCenterCrop(@NonNull ImageView imageView) {
public static void setClipBounds(@NonNull View view, int left, int top, int right, int bottom) {
view.setClipBounds(new Rect(left, top, right, bottom));
}
+
+ /**
+ * Checks if the provided context's underlying Activity is destroyed or finishing.
+ * This is used to prevent Glide crashes when attempting to load images after activity destruction.
+ * @param context The context to check
+ * @return true if the context is destroyed, false otherwise
+ */
+ public static boolean isContextDestroyed(Context context) {
+ Activity activity = getActivity(context);
+ if (activity != null) {
+ if (activity.isFinishing() || activity.isDestroyed()) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Extracts the Activity from a Context, handling ContextWrapper chains.
+ * @param context The context to extract the Activity from
+ * @return The Activity if found, null otherwise
+ */
+ private static Activity getActivity(Context context) {
+ if (context == null) {
+ return null;
+ }
+ if (context instanceof Activity) {
+ return (Activity) context;
+ }
+ if (context instanceof ContextWrapper) {
+ Context baseContext = ((ContextWrapper) context).getBaseContext();
+ return getActivity(baseContext);
+ }
+ return null;
+ }
}
diff --git a/src/Core/AndroidNative/maui/src/main/java/com/microsoft/maui/glide/MauiCustomTarget.java b/src/Core/AndroidNative/maui/src/main/java/com/microsoft/maui/glide/MauiCustomTarget.java
index 21129ce2d40a..2d75dad75dd4 100644
--- a/src/Core/AndroidNative/maui/src/main/java/com/microsoft/maui/glide/MauiCustomTarget.java
+++ b/src/Core/AndroidNative/maui/src/main/java/com/microsoft/maui/glide/MauiCustomTarget.java
@@ -1,8 +1,6 @@
package com.microsoft.maui.glide;
-import android.app.Activity;
import android.content.Context;
-import android.content.ContextWrapper;
import android.graphics.drawable.Drawable;
import android.os.Handler;
import android.os.Looper;
@@ -16,6 +14,7 @@
import com.bumptech.glide.request.transition.Transition;
import com.microsoft.maui.ImageLoaderCallback;
+import com.microsoft.maui.PlatformInterop;
import com.microsoft.maui.PlatformLogger;
import com.microsoft.maui.glide.MauiTarget;
@@ -82,35 +81,11 @@ private void post(Runnable runnable) {
handler.post(runnable);
}
- private static boolean isContextDestroyed(Context context) {
- Activity activity = getActivity(context);
- if (activity != null) {
- if (activity.isFinishing() || activity.isDestroyed()) {
- return true;
- }
- }
- return false;
- }
-
- private static Activity getActivity(Context context) {
- if (context == null) {
- return null;
- }
- if (context instanceof Activity) {
- return (Activity) context;
- }
- if (context instanceof ContextWrapper) {
- Context baseContext = ((ContextWrapper) context).getBaseContext();
- return getActivity(baseContext);
- }
- return null;
- }
-
private void clear() {
// TODO: it looks like no one is really disposing the result on C# side
// we must fix it there to release the Glide cache entry properly
post(() -> {
- if (isContextDestroyed(context)) {
+ if (PlatformInterop.isContextDestroyed(context)) {
if (logger.isVerboseLoggable) {
logger.v("clear() skipped - context destroyed: " + resourceLogIdentifier);
}