Skip to content

Commit

Permalink
Move Glide Registry initialization to a background thread.
Browse files Browse the repository at this point in the history
By making the Registry lazy, we defer initialization until the first time it's used, which will be during the first request to load an image. Since image loads only happen on Glide's background threads, this effectively moves initialization from the UI thread to a background thread.

PiperOrigin-RevId: 429678596
  • Loading branch information
sjudd authored and glide-copybara-robot committed Feb 19, 2022
1 parent edf9d32 commit 6ba4b54
Show file tree
Hide file tree
Showing 6 changed files with 145 additions and 46 deletions.
52 changes: 25 additions & 27 deletions library/src/main/java/com/bumptech/glide/Glide.java
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
import androidx.annotation.VisibleForTesting;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentActivity;
import com.bumptech.glide.GlideBuilder.EnableLazyGlideRegistry;
import com.bumptech.glide.load.DecodeFormat;
import com.bumptech.glide.load.engine.Engine;
import com.bumptech.glide.load.engine.bitmap_recycle.ArrayPool;
Expand All @@ -26,11 +27,14 @@
import com.bumptech.glide.load.resource.bitmap.HardwareConfigState;
import com.bumptech.glide.manager.ConnectivityMonitorFactory;
import com.bumptech.glide.manager.RequestManagerRetriever;
import com.bumptech.glide.module.AppGlideModule;
import com.bumptech.glide.module.GlideModule;
import com.bumptech.glide.module.ManifestParser;
import com.bumptech.glide.request.RequestListener;
import com.bumptech.glide.request.RequestOptions;
import com.bumptech.glide.request.target.ImageViewTargetFactory;
import com.bumptech.glide.request.target.Target;
import com.bumptech.glide.util.GlideSuppliers.GlideSupplier;
import com.bumptech.glide.util.Preconditions;
import com.bumptech.glide.util.Util;
import java.io.File;
Expand Down Expand Up @@ -210,17 +214,17 @@ private static void initializeGlide(
@NonNull GlideBuilder builder,
@Nullable GeneratedAppGlideModule annotationGeneratedModule) {
Context applicationContext = context.getApplicationContext();
List<com.bumptech.glide.module.GlideModule> manifestModules = Collections.emptyList();
List<GlideModule> manifestModules = Collections.emptyList();
if (annotationGeneratedModule == null || annotationGeneratedModule.isManifestParsingEnabled()) {
manifestModules = new ManifestParser(applicationContext).parse();
}

if (annotationGeneratedModule != null
&& !annotationGeneratedModule.getExcludedModuleClasses().isEmpty()) {
Set<Class<?>> excludedModuleClasses = annotationGeneratedModule.getExcludedModuleClasses();
Iterator<com.bumptech.glide.module.GlideModule> iterator = manifestModules.iterator();
Iterator<GlideModule> iterator = manifestModules.iterator();
while (iterator.hasNext()) {
com.bumptech.glide.module.GlideModule current = iterator.next();
GlideModule current = iterator.next();
if (!excludedModuleClasses.contains(current.getClass())) {
continue;
}
Expand All @@ -232,7 +236,7 @@ private static void initializeGlide(
}

if (Log.isLoggable(TAG, Log.DEBUG)) {
for (com.bumptech.glide.module.GlideModule glideModule : manifestModules) {
for (GlideModule glideModule : manifestModules) {
Log.d(TAG, "Discovered GlideModule from manifest: " + glideModule.getClass());
}
}
Expand All @@ -242,31 +246,20 @@ private static void initializeGlide(
? annotationGeneratedModule.getRequestManagerFactory()
: null;
builder.setRequestManagerFactory(factory);
for (com.bumptech.glide.module.GlideModule module : manifestModules) {
for (GlideModule module : manifestModules) {
module.applyOptions(applicationContext, builder);
}
if (annotationGeneratedModule != null) {
annotationGeneratedModule.applyOptions(applicationContext, builder);
}
Glide glide = builder.build(applicationContext);
for (com.bumptech.glide.module.GlideModule module : manifestModules) {
try {
module.registerComponents(applicationContext, glide, glide.glideContext.getRegistry());
} catch (AbstractMethodError e) {
throw new IllegalStateException(
"Attempting to register a Glide v3 module. If you see this, you or one of your"
+ " dependencies may be including Glide v3 even though you're using Glide v4."
+ " You'll need to find and remove (or update) the offending dependency."
+ " The v3 module name is: "
+ module.getClass().getName(),
e);
}
}
if (annotationGeneratedModule != null) {
annotationGeneratedModule.registerComponents(
applicationContext, glide, glide.glideContext.getRegistry());
}
Glide glide = builder.build(applicationContext, manifestModules, annotationGeneratedModule);
applicationContext.registerComponentCallbacks(glide);

// Trigger the registry initialization eagerly, similar to the codepath prior to the experiment.
if (!glide.getGlideContext().getExperiments().isEnabled(EnableLazyGlideRegistry.class)) {
glide.getGlideContext().getRegistry();
}

Glide.glide = glide;
}

Expand Down Expand Up @@ -323,7 +316,9 @@ private static void throwIncorrectGlideModule(Exception e) {
@NonNull RequestOptionsFactory defaultRequestOptionsFactory,
@NonNull Map<Class<?>, TransitionOptions<?, ?>> defaultTransitionOptions,
@NonNull List<RequestListener<Object>> defaultRequestListeners,
GlideExperiments experiments) {
@NonNull List<GlideModule> manifestModules,
@Nullable AppGlideModule annotationGeneratedModule,
@NonNull GlideExperiments experiments) {
this.engine = engine;
this.bitmapPool = bitmapPool;
this.arrayPool = arrayPool;
Expand All @@ -332,9 +327,12 @@ private static void throwIncorrectGlideModule(Exception e) {
this.connectivityMonitorFactory = connectivityMonitorFactory;
this.defaultRequestOptionsFactory = defaultRequestOptionsFactory;

Registry registry =
RegistryFactory.createRegistryAndInitializeDefaults(
context, bitmapPool, arrayPool, experiments);
// 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.
GlideSupplier<Registry> registry =
RegistryFactory.lazilyCreateAndInitializeRegistry(
this, manifestModules, annotationGeneratedModule);

ImageViewTargetFactory imageViewTargetFactory = new ImageViewTargetFactory();
glideContext =
Expand Down
11 changes: 10 additions & 1 deletion library/src/main/java/com/bumptech/glide/GlideBuilder.java
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@
import com.bumptech.glide.manager.DefaultConnectivityMonitorFactory;
import com.bumptech.glide.manager.RequestManagerRetriever;
import com.bumptech.glide.manager.RequestManagerRetriever.RequestManagerFactory;
import com.bumptech.glide.module.AppGlideModule;
import com.bumptech.glide.module.GlideModule;
import com.bumptech.glide.request.BaseRequestOptions;
import com.bumptech.glide.request.RequestListener;
import com.bumptech.glide.request.RequestOptions;
Expand Down Expand Up @@ -504,7 +506,10 @@ GlideBuilder setEngine(Engine engine) {
}

@NonNull
Glide build(@NonNull Context context) {
Glide build(
@NonNull Context context,
List<GlideModule> manifestModules,
AppGlideModule annotationGeneratedGlideModule) {
if (sourceExecutor == null) {
sourceExecutor = GlideExecutor.newSourceExecutor();
}
Expand Down Expand Up @@ -580,6 +585,8 @@ Glide build(@NonNull Context context) {
defaultRequestOptionsFactory,
defaultTransitionOptions,
defaultRequestListeners,
manifestModules,
annotationGeneratedGlideModule,
experiments);
}

Expand All @@ -603,4 +610,6 @@ static final class EnableImageDecoderForAnimatedWebp implements Experiment {}

/** See {@link #setLogRequestOrigins(boolean)}. */
public static final class LogRequestOrigins implements Experiment {}

static final class EnableLazyGlideRegistry implements Experiment {}
}
11 changes: 7 additions & 4 deletions library/src/main/java/com/bumptech/glide/GlideContext.java
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@
import com.bumptech.glide.request.RequestOptions;
import com.bumptech.glide.request.target.ImageViewTargetFactory;
import com.bumptech.glide.request.target.ViewTarget;
import com.bumptech.glide.util.GlideSuppliers;
import com.bumptech.glide.util.GlideSuppliers.GlideSupplier;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
Expand All @@ -29,7 +31,7 @@ public class GlideContext extends ContextWrapper {
new GenericTransitionOptions<>();

private final ArrayPool arrayPool;
private final Registry registry;
private final GlideSupplier<Registry> registry;
private final ImageViewTargetFactory imageViewTargetFactory;
private final RequestOptionsFactory defaultRequestOptionsFactory;
private final List<RequestListener<Object>> defaultRequestListeners;
Expand All @@ -45,7 +47,7 @@ public class GlideContext extends ContextWrapper {
public GlideContext(
@NonNull Context context,
@NonNull ArrayPool arrayPool,
@NonNull Registry registry,
@NonNull GlideSupplier<Registry> registry,
@NonNull ImageViewTargetFactory imageViewTargetFactory,
@NonNull RequestOptionsFactory defaultRequestOptionsFactory,
@NonNull Map<Class<?>, TransitionOptions<?, ?>> defaultTransitionOptions,
Expand All @@ -55,14 +57,15 @@ public GlideContext(
int logLevel) {
super(context.getApplicationContext());
this.arrayPool = arrayPool;
this.registry = registry;
this.imageViewTargetFactory = imageViewTargetFactory;
this.defaultRequestOptionsFactory = defaultRequestOptionsFactory;
this.defaultRequestListeners = defaultRequestListeners;
this.defaultTransitionOptions = defaultTransitionOptions;
this.engine = engine;
this.experiments = experiments;
this.logLevel = logLevel;

this.registry = GlideSuppliers.memorize(registry);
}

public List<RequestListener<Object>> getDefaultRequestListeners() {
Expand Down Expand Up @@ -107,7 +110,7 @@ public Engine getEngine() {

@NonNull
public Registry getRegistry() {
return registry;
return registry.get();
}

public int getLogLevel() {
Expand Down
82 changes: 79 additions & 3 deletions library/src/main/java/com/bumptech/glide/RegistryFactory.java
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@
import android.net.Uri;
import android.os.Build;
import android.os.ParcelFileDescriptor;
import androidx.annotation.Nullable;
import androidx.tracing.Trace;
import com.bumptech.glide.GlideBuilder.EnableImageDecoderForAnimatedWebp;
import com.bumptech.glide.GlideBuilder.EnableImageDecoderForBitmaps;
import com.bumptech.glide.gifdecoder.GifDecoder;
Expand Down Expand Up @@ -66,6 +68,10 @@
import com.bumptech.glide.load.resource.transcode.BitmapDrawableTranscoder;
import com.bumptech.glide.load.resource.transcode.DrawableBytesTranscoder;
import com.bumptech.glide.load.resource.transcode.GifDrawableBytesTranscoder;
import com.bumptech.glide.module.AppGlideModule;
import com.bumptech.glide.module.GlideModule;
import com.bumptech.glide.util.GlideSuppliers.GlideSupplier;
import com.bumptech.glide.util.Synthetic;
import java.io.File;
import java.io.InputStream;
import java.net.URL;
Expand All @@ -76,9 +82,57 @@ final class RegistryFactory {

private RegistryFactory() {}

static Registry createRegistryAndInitializeDefaults(
Context context, BitmapPool bitmapPool, ArrayPool arrayPool, GlideExperiments experiments) {
static GlideSupplier<Registry> lazilyCreateAndInitializeRegistry(
final Glide glide,
final List<GlideModule> manifestModules,
@Nullable final AppGlideModule annotationGeneratedModule) {
return new GlideSupplier<Registry>() {
private boolean isInitializingOrInitialized;

@Override
public Registry get() {
if (isInitializingOrInitialized) {
throw new IllegalStateException(
"Recursive Registry initialization! In your"
+ " AppGlideModule and LibraryGlideModules, Make sure you're using the provided "
+ "Registry rather calling glide.getRegistry()!");
}
isInitializingOrInitialized = true;

Trace.beginSection("Glide registry");
try {
return createAndInitRegistry(glide, manifestModules, annotationGeneratedModule);
} finally {
Trace.endSection();
}
}
};
}

@Synthetic
static Registry createAndInitRegistry(
Glide glide,
List<GlideModule> manifestModules,
@Nullable AppGlideModule annotationGeneratedModule) {

BitmapPool bitmapPool = glide.getBitmapPool();
ArrayPool arrayPool = glide.getArrayPool();
Context context = glide.getGlideContext().getApplicationContext();

GlideExperiments experiments = glide.getGlideContext().getExperiments();

Registry registry = new Registry();
initializeDefaults(context, registry, bitmapPool, arrayPool, experiments);
initializeModules(context, glide, registry, manifestModules, annotationGeneratedModule);
return registry;
}

private static void initializeDefaults(
Context context,
Registry registry,
BitmapPool bitmapPool,
ArrayPool arrayPool,
GlideExperiments experiments) {
registry.register(new DefaultImageHeaderParser());
// Right now we're only using this parser for HEIF images, which are only supported on OMR1+.
// If we need this for other file types, we should consider removing this restriction.
Expand Down Expand Up @@ -290,7 +344,29 @@ Uri.class, Bitmap.class, new ResourceBitmapDecoder(resourceDrawableDecoder, bitm
BitmapDrawable.class,
new BitmapDrawableDecoder<>(resources, byteBufferVideoDecoder));
}
}

return registry;
private static void initializeModules(
Context context,
Glide glide,
Registry registry,
List<GlideModule> manifestModules,
@Nullable AppGlideModule annotationGeneratedModule) {
for (GlideModule module : manifestModules) {
try {
module.registerComponents(context, glide, registry);
} catch (AbstractMethodError e) {
throw new IllegalStateException(
"Attempting to register a Glide v3 module. If you see this, you or one of your"
+ " dependencies may be including Glide v3 even though you're using Glide v4."
+ " You'll need to find and remove (or update) the offending dependency."
+ " The v3 module name is: "
+ module.getClass().getName(),
e);
}
}
if (annotationGeneratedModule != null) {
annotationGeneratedModule.registerComponents(context, glide, registry);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
import com.bumptech.glide.request.RequestListener;
import com.bumptech.glide.request.RequestOptions;
import com.bumptech.glide.request.target.ImageViewTargetFactory;
import com.bumptech.glide.util.GlideSuppliers.GlideSupplier;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
Expand All @@ -40,7 +41,12 @@ public void setUp() {
new GlideContext(
app,
new LruArrayPool(),
new Registry(),
new GlideSupplier<Registry>() {
@Override
public Registry get() {
return new Registry();
}
},
new ImageViewTargetFactory(),
new RequestOptionsFactory() {
@NonNull
Expand Down
Loading

0 comments on commit 6ba4b54

Please sign in to comment.