diff --git a/library/src/main/java/com/bumptech/glide/Glide.java b/library/src/main/java/com/bumptech/glide/Glide.java index 8a5288aa4b..aebf9ae16a 100644 --- a/library/src/main/java/com/bumptech/glide/Glide.java +++ b/library/src/main/java/com/bumptech/glide/Glide.java @@ -1,10 +1,12 @@ package com.bumptech.glide; import android.app.Activity; +import android.app.Application; import android.content.ComponentCallbacks2; import android.content.Context; import android.content.res.Configuration; import android.graphics.Bitmap; +import android.os.Bundle; import android.os.MessageQueue.IdleHandler; import android.util.Log; import android.view.View; @@ -50,7 +52,7 @@ * RequestBuilder} and maintaining an {@link Engine}, {@link BitmapPool}, {@link * com.bumptech.glide.load.engine.cache.DiskCache} and {@link MemoryCache}. */ -public class Glide implements ComponentCallbacks2 { +public class Glide implements ComponentCallbacks2, Application.ActivityLifecycleCallbacks { private static final String DEFAULT_DISK_CACHE_DIR = "image_manager_disk_cache"; private static final String DESTROYED_ACTIVITY_WARNING = "You cannot start a load on a not yet attached View or a Fragment where getActivity() " @@ -77,6 +79,9 @@ public class Glide implements ComponentCallbacks2 { private final RequestOptionsFactory defaultRequestOptionsFactory; private MemoryCategory memoryCategory = MemoryCategory.NORMAL; + private final MemoryCategory memoryCategoryInBackground; + private boolean inBackground; + @GuardedBy("this") @Nullable private BitmapPreFiller bitmapPreFiller; @@ -205,7 +210,9 @@ public static void enableHardwareBitmaps() { public static void tearDown() { synchronized (Glide.class) { if (glide != null) { - glide.getContext().getApplicationContext().unregisterComponentCallbacks(glide); + Application application = (Application) glide.getContext().getApplicationContext(); + application.unregisterActivityLifecycleCallbacks(glide); + application.unregisterComponentCallbacks(glide); glide.engine.shutdown(); } glide = null; @@ -224,7 +231,7 @@ private static void initializeGlide( @NonNull Context context, @NonNull GlideBuilder builder, @Nullable GeneratedAppGlideModule annotationGeneratedModule) { - Context applicationContext = context.getApplicationContext(); + Application applicationContext = (Application) context.getApplicationContext(); List manifestModules = Collections.emptyList(); if (annotationGeneratedModule == null || annotationGeneratedModule.isManifestParsingEnabled()) { manifestModules = new ManifestParser(applicationContext).parse(); @@ -265,6 +272,7 @@ private static void initializeGlide( } Glide glide = builder.build(applicationContext, manifestModules, annotationGeneratedModule); applicationContext.registerComponentCallbacks(glide); + applicationContext.registerActivityLifecycleCallbacks(glide); Glide.glide = glide; } @@ -332,6 +340,11 @@ private static void throwIncorrectGlideModule(Exception e) { this.connectivityMonitorFactory = connectivityMonitorFactory; this.defaultRequestOptionsFactory = defaultRequestOptionsFactory; + GlideBuilder.MemoryCategoryInBackground memoryCategoryInBackground = + experiments.get(GlideBuilder.MemoryCategoryInBackground.class); + this.memoryCategoryInBackground = memoryCategoryInBackground != null ? + memoryCategoryInBackground.value() : null; + // This has a circular relationship with Glide and GlideContext in that it depends on both, // but it's created by Glide's constructor. In practice this shouldn't matter because the // supplier holding the registry should never be initialized before this constructor finishes. @@ -678,6 +691,12 @@ void unregisterRequestManager(RequestManager requestManager) { @Override public void onTrimMemory(int level) { trimMemory(level); + // when level is TRIM_MEMORY_UI_HIDDEN or higher, it indicates that the app + // is in the background, limit the memory usage by set memory category + if (memoryCategoryInBackground != null && level >= TRIM_MEMORY_UI_HIDDEN) { + inBackground = true; + setMemoryCategory(memoryCategoryInBackground); + } } @Override @@ -697,4 +716,47 @@ public interface RequestOptionsFactory { @NonNull RequestOptions build(); } + + /** + * Any activity started or resumed indicates that the app is no longer + * in the background, and the memory category needs to be restored. + */ + @Override + public void onActivityStarted(Activity activity) { + if (memoryCategoryInBackground != null && inBackground) { + setMemoryCategory(MemoryCategory.NORMAL); + } + } + + @Override + public void onActivityResumed(Activity activity) { + if (memoryCategoryInBackground != null && inBackground) { + setMemoryCategory(MemoryCategory.NORMAL); + } + } + + @Override + public void onActivityCreated(Activity activity, Bundle savedIntsanceState) { + // Do nothing. + } + + @Override + public void onActivityDestroyed(Activity activity) { + // Do nothing. + } + + @Override + public void onActivityStopped(Activity activity) { + // Do nothing. + } + + @Override + public void onActivitySaveInstanceState(Activity activity, Bundle outState) { + // Do nothing. + } + + @Override + public void onActivityPaused(Activity activity) { + // Do nothing. + } } diff --git a/library/src/main/java/com/bumptech/glide/GlideBuilder.java b/library/src/main/java/com/bumptech/glide/GlideBuilder.java index 94a774122a..d54972cfe1 100644 --- a/library/src/main/java/com/bumptech/glide/GlideBuilder.java +++ b/library/src/main/java/com/bumptech/glide/GlideBuilder.java @@ -539,6 +539,15 @@ public GlideBuilder setDisableHardwareBitmapsOnO(boolean disableHardwareBitmapsO return this; } + /** + * This method sets the memory category when the app is in the background. + */ + public GlideBuilder setMemoryCategoryInBackground(@Nullable MemoryCategory category) { + glideExperimentsBuilder.update(new MemoryCategoryInBackground(category), + category != null ? true : false); + return this; + } + void setRequestManagerFactory(@Nullable RequestManagerFactory factory) { this.requestManagerFactory = factory; } @@ -653,4 +662,16 @@ public static final class OverrideGlideThreadPriority implements Experiment {} /** See {@link #setUseMediaStoreOpenFileApisIfPossible(boolean)}. */ public static final class UseMediaStoreOpenFileApisIfPossible implements Experiment {} + + public static final class MemoryCategoryInBackground implements Experiment { + private final MemoryCategory category; + + public MemoryCategoryInBackground(MemoryCategory category) { + this.category = category; + } + + public MemoryCategory value() { + return this.category; + } + } } diff --git a/library/src/main/java/com/bumptech/glide/MemoryCategory.java b/library/src/main/java/com/bumptech/glide/MemoryCategory.java index 0e71072059..5d0398978e 100644 --- a/library/src/main/java/com/bumptech/glide/MemoryCategory.java +++ b/library/src/main/java/com/bumptech/glide/MemoryCategory.java @@ -2,6 +2,10 @@ /** An enum for dynamically modifying the amount of memory Glide is able to use. */ public enum MemoryCategory { + /** + * Tells Glide's memory cache and bitmap pool to use no memory. + */ + ZERO(0.0f), /** * Tells Glide's memory cache and bitmap pool to use at most half of their initial maximum size. */