11package com .bumptech .glide ;
22
33import android .app .Activity ;
4+ import android .app .Application ;
45import android .content .ComponentCallbacks2 ;
56import android .content .Context ;
67import android .content .res .Configuration ;
78import android .graphics .Bitmap ;
9+ import android .os .Bundle ;
810import android .os .MessageQueue .IdleHandler ;
911import android .util .Log ;
1012import android .view .View ;
3335import com .bumptech .glide .request .RequestOptions ;
3436import com .bumptech .glide .request .target .ImageViewTargetFactory ;
3537import com .bumptech .glide .request .target .Target ;
38+ import com .bumptech .glide .util .GlideSuppliers ;
3639import com .bumptech .glide .util .GlideSuppliers .GlideSupplier ;
3740import com .bumptech .glide .util .Preconditions ;
3841import 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.
@@ -206,6 +216,7 @@ public static void tearDown() {
206216 synchronized (Glide .class ) {
207217 if (glide != null ) {
208218 glide .getContext ().getApplicationContext ().unregisterComponentCallbacks (glide );
219+ glide .unregisterActivityLifecycleCallbacks ();
209220 glide .engine .shutdown ();
210221 }
211222 glide = null ;
@@ -265,6 +276,7 @@ private static void initializeGlide(
265276 }
266277 Glide glide = builder .build (applicationContext , manifestModules , annotationGeneratedModule );
267278 applicationContext .registerComponentCallbacks (glide );
279+ glide .registerActivityLifecycleCallbacks ();
268280 Glide .glide = glide ;
269281 }
270282
@@ -332,6 +344,12 @@ private static void throwIncorrectGlideModule(Exception e) {
332344 this .connectivityMonitorFactory = connectivityMonitorFactory ;
333345 this .defaultRequestOptionsFactory = defaultRequestOptionsFactory ;
334346
347+ GlideBuilder .MemoryCategoryInBackground memoryCategoryInBackground =
348+ experiments .get (GlideBuilder .MemoryCategoryInBackground .class );
349+ if (memoryCategoryInBackground != null ) {
350+ this .memoryCategoryInBackground = memoryCategoryInBackground .value ();
351+ }
352+
335353 // This has a circular relationship with Glide and GlideContext in that it depends on both,
336354 // but it's created by Glide's constructor. In practice this shouldn't matter because the
337355 // supplier holding the registry should never be initialized before this constructor finishes.
@@ -678,6 +696,11 @@ void unregisterRequestManager(RequestManager requestManager) {
678696 @ Override
679697 public void onTrimMemory (int level ) {
680698 trimMemory (level );
699+ // when level is TRIM_MEMORY_UI_HIDDEN or higher, it indicates that the app is
700+ // in the background, limit the memory usage by memoryCategoryInBackground.
701+ if (level >= TRIM_MEMORY_UI_HIDDEN ) {
702+ setMemoryCategoryWhenInBackground ();
703+ }
681704 }
682705
683706 @ Override
@@ -697,4 +720,85 @@ public interface RequestOptionsFactory {
697720 @ NonNull
698721 RequestOptions build ();
699722 }
723+
724+ private void registerActivityLifecycleCallbacks () {
725+ if (memoryCategoryInBackground != null ) {
726+ Context context = getContext ().getApplicationContext ();
727+ if (!(context instanceof Application ) && Log .isLoggable (TAG , Log .WARN )) {
728+ Log .w (
729+ TAG ,
730+ "Glide requires an Application Context. You passed: "
731+ + context
732+ + ". This will disable setting memory category in background." );
733+ return ;
734+ }
735+ ((Application ) context ).registerActivityLifecycleCallbacks (setMemoryCategoryCallbacks .get ());
736+ }
737+ }
738+
739+ private void unregisterActivityLifecycleCallbacks () {
740+ if (memoryCategoryInBackground != null ) {
741+ Context context = getContext ().getApplicationContext ();
742+ if (context instanceof Application ) {
743+ ((Application ) context )
744+ .unregisterActivityLifecycleCallbacks (setMemoryCategoryCallbacks .get ());
745+ }
746+ }
747+ }
748+
749+ private void setMemoryCategoryWhenInBackground () {
750+ if (memoryCategoryInBackground == null || inBackground ) {
751+ return ;
752+ }
753+ inBackground = true ;
754+ memoryCategoryInForeground = setMemoryCategory (memoryCategoryInBackground );
755+ }
756+
757+ private void setMemoryCategoryWhenInForeground () {
758+ if (memoryCategoryInBackground == null || !inBackground ) {
759+ return ;
760+ }
761+ inBackground = false ;
762+ setMemoryCategory (memoryCategoryInForeground );
763+ }
764+
765+ private final class SetMemoryCategoryOnLifecycleCallbacks
766+ implements Application .ActivityLifecycleCallbacks {
767+ @ Override
768+ public void onActivityStarted (Activity activity ) {
769+ // Do nothing.
770+ }
771+
772+ @ Override
773+ public void onActivityResumed (Activity activity ) {
774+ // Any activity resumed indicates that the app is no longer in the background,
775+ // and we should restore the memory usage to normal.
776+ setMemoryCategoryWhenInForeground ();
777+ }
778+
779+ @ Override
780+ public void onActivityCreated (Activity activity , Bundle savedInstanceState ) {
781+ // Do nothing.
782+ }
783+
784+ @ Override
785+ public void onActivityDestroyed (Activity activity ) {
786+ // Do nothing.
787+ }
788+
789+ @ Override
790+ public void onActivityStopped (Activity activity ) {
791+ // Do nothing.
792+ }
793+
794+ @ Override
795+ public void onActivitySaveInstanceState (Activity activity , Bundle outState ) {
796+ // Do nothing.
797+ }
798+
799+ @ Override
800+ public void onActivityPaused (Activity activity ) {
801+ // Do nothing.
802+ }
803+ }
700804}
0 commit comments