Skip to content

Commit d591539

Browse files
falhassenglide-copybara-robot
authored andcommitted
Allow limiting the size of LruBitmapPool/MemoryCache when in background
When an app is moved to background, onTrimMemory() will be called, and LruBitmapPool/MemoryCache will be trimmed. However, the app could keep running and will new bitmaps will be retired to MemoryCache and LruBitmapPool. This change limits the sizes of LruBitmapPool/MemoryCache to zero when the app is in background, and restore the sizes to normal when it's moved out of background. We introduce an experimental API `setMemoryCategoryInBackground(MemoryCategory)` for this purpose, as well as a new `MemoryCategory.ZERO` for no pooling/caching. App can use this API to set the MemoryCategory to limit the pool/cache size when the app is in background. PiperOrigin-RevId: 852864309
1 parent 5e15812 commit d591539

File tree

3 files changed

+122
-2
lines changed

3 files changed

+122
-2
lines changed

library/src/main/java/com/bumptech/glide/Glide.java

Lines changed: 96 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,12 @@
11
package com.bumptech.glide;
22

33
import android.app.Activity;
4+
import android.app.Application;
45
import android.content.ComponentCallbacks2;
56
import android.content.Context;
67
import android.content.res.Configuration;
78
import android.graphics.Bitmap;
9+
import android.os.Bundle;
810
import android.os.MessageQueue.IdleHandler;
911
import android.util.Log;
1012
import android.view.View;
@@ -33,6 +35,7 @@
3335
import com.bumptech.glide.request.RequestOptions;
3436
import com.bumptech.glide.request.target.ImageViewTargetFactory;
3537
import com.bumptech.glide.request.target.Target;
38+
import com.bumptech.glide.util.GlideSuppliers;
3639
import com.bumptech.glide.util.GlideSuppliers.GlideSupplier;
3740
import com.bumptech.glide.util.Preconditions;
3841
import com.bumptech.glide.util.Util;
@@ -81,6 +84,13 @@ public class Glide implements ComponentCallbacks2 {
8184
@Nullable
8285
private BitmapPreFiller bitmapPreFiller;
8386

87+
private boolean inBackground = false;
88+
private MemoryCategory memoryCategoryInBackground = null;
89+
private MemoryCategory memoryCategoryInForeground = MemoryCategory.NORMAL;
90+
91+
private final GlideSupplier<SetMemoryCategoryOnLifecycleCallbacks> setMemoryCategoryCallbacks =
92+
GlideSuppliers.memorize(SetMemoryCategoryOnLifecycleCallbacks::new);
93+
8494
/**
8595
* Returns a directory with a default name in the private cache directory of the application to
8696
* use to store retrieved media and thumbnails.
@@ -205,7 +215,9 @@ public static void enableHardwareBitmaps() {
205215
public static void tearDown() {
206216
synchronized (Glide.class) {
207217
if (glide != null) {
208-
glide.getContext().getApplicationContext().unregisterComponentCallbacks(glide);
218+
Application application = (Application) glide.getContext().getApplicationContext();
219+
application.unregisterComponentCallbacks(glide);
220+
glide.unregisterActivityLifecycleCallbacks();
209221
glide.engine.shutdown();
210222
}
211223
glide = null;
@@ -224,7 +236,7 @@ private static void initializeGlide(
224236
@NonNull Context context,
225237
@NonNull GlideBuilder builder,
226238
@Nullable GeneratedAppGlideModule annotationGeneratedModule) {
227-
Context applicationContext = context.getApplicationContext();
239+
Application applicationContext = (Application) context.getApplicationContext();
228240
List<GlideModule> manifestModules = Collections.emptyList();
229241
if (annotationGeneratedModule == null || annotationGeneratedModule.isManifestParsingEnabled()) {
230242
manifestModules = new ManifestParser(applicationContext).parse();
@@ -265,6 +277,7 @@ private static void initializeGlide(
265277
}
266278
Glide glide = builder.build(applicationContext, manifestModules, annotationGeneratedModule);
267279
applicationContext.registerComponentCallbacks(glide);
280+
glide.registerActivityLifecycleCallbacks();
268281
Glide.glide = glide;
269282
}
270283

@@ -332,6 +345,12 @@ private static void throwIncorrectGlideModule(Exception e) {
332345
this.connectivityMonitorFactory = connectivityMonitorFactory;
333346
this.defaultRequestOptionsFactory = defaultRequestOptionsFactory;
334347

348+
GlideBuilder.MemoryCategoryInBackground memoryCategoryInBackground =
349+
experiments.get(GlideBuilder.MemoryCategoryInBackground.class);
350+
if (memoryCategoryInBackground != null) {
351+
this.memoryCategoryInBackground = memoryCategoryInBackground.value();
352+
}
353+
335354
// This has a circular relationship with Glide and GlideContext in that it depends on both,
336355
// but it's created by Glide's constructor. In practice this shouldn't matter because the
337356
// supplier holding the registry should never be initialized before this constructor finishes.
@@ -354,6 +373,20 @@ private static void throwIncorrectGlideModule(Exception e) {
354373
logLevel);
355374
}
356375

376+
private void registerActivityLifecycleCallbacks() {
377+
if (memoryCategoryInBackground != null) {
378+
Application context = (Application) getContext().getApplicationContext();
379+
context.registerActivityLifecycleCallbacks(setMemoryCategoryCallbacks.get());
380+
}
381+
}
382+
383+
private void unregisterActivityLifecycleCallbacks() {
384+
if (memoryCategoryInBackground != null) {
385+
Application context = (Application) getContext().getApplicationContext();
386+
context.unregisterActivityLifecycleCallbacks(setMemoryCategoryCallbacks.get());
387+
}
388+
}
389+
357390
/**
358391
* Returns the {@link com.bumptech.glide.load.engine.bitmap_recycle.BitmapPool} used to
359392
* temporarily store {@link android.graphics.Bitmap}s so they can be reused to avoid garbage
@@ -675,9 +708,30 @@ void unregisterRequestManager(RequestManager requestManager) {
675708
}
676709
}
677710

711+
private void setMemoryCategoryWhenInBackground() {
712+
if (memoryCategoryInBackground == null || inBackground) {
713+
return;
714+
}
715+
inBackground = true;
716+
memoryCategoryInForeground = setMemoryCategory(memoryCategoryInBackground);
717+
}
718+
719+
private void setMemoryCategoryWhenInForeground() {
720+
if (memoryCategoryInBackground == null || !inBackground) {
721+
return;
722+
}
723+
inBackground = false;
724+
setMemoryCategory(memoryCategoryInForeground);
725+
}
726+
678727
@Override
679728
public void onTrimMemory(int level) {
680729
trimMemory(level);
730+
// when level is TRIM_MEMORY_UI_HIDDEN or higher, it indicates that the app is
731+
// in the background, limit the memory usage by memoryCategoryInBackground.
732+
if (level >= TRIM_MEMORY_UI_HIDDEN) {
733+
setMemoryCategoryWhenInBackground();
734+
}
681735
}
682736

683737
@Override
@@ -697,4 +751,44 @@ public interface RequestOptionsFactory {
697751
@NonNull
698752
RequestOptions build();
699753
}
754+
755+
private final class SetMemoryCategoryOnLifecycleCallbacks
756+
implements Application.ActivityLifecycleCallbacks {
757+
@Override
758+
public void onActivityStarted(Activity activity) {
759+
// Do nothing.
760+
}
761+
762+
@Override
763+
public void onActivityResumed(Activity activity) {
764+
// Any activity resumed indicates that the app is no longer in the background,
765+
// and we should restore the memory usage to normal.
766+
setMemoryCategoryWhenInForeground();
767+
}
768+
769+
@Override
770+
public void onActivityCreated(Activity activity, Bundle savedInstanceState) {
771+
// Do nothing.
772+
}
773+
774+
@Override
775+
public void onActivityDestroyed(Activity activity) {
776+
// Do nothing.
777+
}
778+
779+
@Override
780+
public void onActivityStopped(Activity activity) {
781+
// Do nothing.
782+
}
783+
784+
@Override
785+
public void onActivitySaveInstanceState(Activity activity, Bundle outState) {
786+
// Do nothing.
787+
}
788+
789+
@Override
790+
public void onActivityPaused(Activity activity) {
791+
// Do nothing.
792+
}
793+
}
700794
}

library/src/main/java/com/bumptech/glide/GlideBuilder.java

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -512,6 +512,17 @@ public GlideBuilder setUseMediaStoreOpenFileApisIfPossible(boolean isEnabled) {
512512
return this;
513513
}
514514

515+
/**
516+
* Set to {@code true} to make Glide use {@link MemoryCategory} to set the memory category when
517+
* the app is in the background.
518+
*
519+
* <p>This is an experimental API that may be removed in the future.
520+
*/
521+
public GlideBuilder setMemoryCategoryInBackground(MemoryCategory memoryCategory) {
522+
glideExperimentsBuilder.add(new MemoryCategoryInBackground(memoryCategory));
523+
return this;
524+
}
525+
515526
/**
516527
* @deprecated This method does nothing. It will be hard coded and removed in a future release
517528
* without further warning.
@@ -653,4 +664,17 @@ public static final class OverrideGlideThreadPriority implements Experiment {}
653664

654665
/** See {@link #setUseMediaStoreOpenFileApisIfPossible(boolean)}. */
655666
public static final class UseMediaStoreOpenFileApisIfPossible implements Experiment {}
667+
668+
/** See {@link #setMemoryCategoryInBackground(MemoryCategory)} */
669+
public static final class MemoryCategoryInBackground implements Experiment {
670+
private final MemoryCategory memoryCategory;
671+
672+
MemoryCategoryInBackground(MemoryCategory memoryCategory) {
673+
this.memoryCategory = memoryCategory;
674+
}
675+
676+
public MemoryCategory value() {
677+
return memoryCategory;
678+
}
679+
}
656680
}

library/src/main/java/com/bumptech/glide/MemoryCategory.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22

33
/** An enum for dynamically modifying the amount of memory Glide is able to use. */
44
public enum MemoryCategory {
5+
/** Tells Glide's memory cache and bitmap pool to use no memory. */
6+
ZERO(0f),
57
/**
68
* Tells Glide's memory cache and bitmap pool to use at most half of their initial maximum size.
79
*/

0 commit comments

Comments
 (0)