com.bumptech.glide.Registry Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of glide Show documentation
Show all versions of glide Show documentation
A fast and efficient image loading library for Android focused on smooth scrolling.
package com.bumptech.glide;
import android.support.v4.util.Pools.Pool;
import com.bumptech.glide.load.Encoder;
import com.bumptech.glide.load.ImageHeaderParser;
import com.bumptech.glide.load.ResourceDecoder;
import com.bumptech.glide.load.ResourceEncoder;
import com.bumptech.glide.load.data.DataRewinder;
import com.bumptech.glide.load.data.DataRewinderRegistry;
import com.bumptech.glide.load.engine.DecodePath;
import com.bumptech.glide.load.engine.LoadPath;
import com.bumptech.glide.load.engine.Resource;
import com.bumptech.glide.load.model.ModelLoader;
import com.bumptech.glide.load.model.ModelLoaderFactory;
import com.bumptech.glide.load.model.ModelLoaderRegistry;
import com.bumptech.glide.load.resource.transcode.ResourceTranscoder;
import com.bumptech.glide.load.resource.transcode.TranscoderRegistry;
import com.bumptech.glide.provider.EncoderRegistry;
import com.bumptech.glide.provider.ImageHeaderParserRegistry;
import com.bumptech.glide.provider.LoadPathCache;
import com.bumptech.glide.provider.ModelToResourceClassCache;
import com.bumptech.glide.provider.ResourceDecoderRegistry;
import com.bumptech.glide.provider.ResourceEncoderRegistry;
import com.bumptech.glide.util.pool.FactoryPools;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
/**
* Manages component registration.
*/
public class Registry {
private final ModelLoaderRegistry modelLoaderRegistry;
private final EncoderRegistry encoderRegistry;
private final ResourceDecoderRegistry decoderRegistry;
private final ResourceEncoderRegistry resourceEncoderRegistry;
private final DataRewinderRegistry dataRewinderRegistry;
private final TranscoderRegistry transcoderRegistry;
private final ImageHeaderParserRegistry imageHeaderParserRegistry;
private final ModelToResourceClassCache modelToResourceClassCache =
new ModelToResourceClassCache();
private final LoadPathCache loadPathCache = new LoadPathCache();
private final Pool> exceptionListPool = FactoryPools.threadSafeList();
public Registry() {
this.modelLoaderRegistry = new ModelLoaderRegistry(exceptionListPool);
this.encoderRegistry = new EncoderRegistry();
this.decoderRegistry = new ResourceDecoderRegistry();
this.resourceEncoderRegistry = new ResourceEncoderRegistry();
this.dataRewinderRegistry = new DataRewinderRegistry();
this.transcoderRegistry = new TranscoderRegistry();
this.imageHeaderParserRegistry = new ImageHeaderParserRegistry();
}
public Registry register(Class dataClass, Encoder encoder) {
encoderRegistry.add(dataClass, encoder);
return this;
}
public Registry append(Class dataClass, Class resourceClass,
ResourceDecoder decoder) {
decoderRegistry.append(decoder, dataClass, resourceClass);
return this;
}
public Registry prepend(Class dataClass, Class resourceClass,
ResourceDecoder decoder) {
decoderRegistry.prepend(decoder, dataClass, resourceClass);
return this;
}
public Registry register(Class resourceClass,
ResourceEncoder encoder) {
resourceEncoderRegistry.add(resourceClass, encoder);
return this;
}
public Registry register(DataRewinder.Factory factory) {
dataRewinderRegistry.register(factory);
return this;
}
public Registry register(Class resourceClass,
Class transcodeClass, ResourceTranscoder transcoder) {
transcoderRegistry.register(resourceClass, transcodeClass, transcoder);
return this;
}
public Registry register(ImageHeaderParser parser) {
imageHeaderParserRegistry.add(parser);
return this;
}
/**
* Use the given factory to build a {@link com.bumptech.glide.load.model.ModelLoader} for models
* of the given class. Generally the best use of this method is to replace one of the default
* factories or add an implementation for other similar low level models. Any factory replaced by
* the given factory will have its {@link ModelLoaderFactory#teardown()}} method called.
*
* Note - If a factory already exists for the given class, it will be replaced. If that
* factory is not being used for any other model class, {@link ModelLoaderFactory#teardown()} will
* be called.
*
* Note - The factory must not be an anonymous inner class of an Activity or another object
* that cannot be retained statically.
*
* @param modelClass The model class.
* @param dataClass the data class.
*/
public Registry append(Class modelClass, Class dataClass,
ModelLoaderFactory factory) {
modelLoaderRegistry.append(modelClass, dataClass, factory);
return this;
}
public Registry prepend(Class modelClass, Class dataClass,
ModelLoaderFactory factory) {
modelLoaderRegistry.prepend(modelClass, dataClass, factory);
return this;
}
public Registry replace(Class modelClass, Class dataClass,
ModelLoaderFactory factory) {
modelLoaderRegistry.replace(modelClass, dataClass, factory);
return this;
}
public LoadPath getLoadPath(
Class dataClass, Class resourceClass, Class transcodeClass) {
LoadPath result =
loadPathCache.get(dataClass, resourceClass, transcodeClass);
if (result == null && !loadPathCache.contains(dataClass, resourceClass, transcodeClass)) {
List> decodePaths =
getDecodePaths(dataClass, resourceClass, transcodeClass);
// It's possible there is no way to decode or transcode to the desired types from a given
// data class.
if (decodePaths.isEmpty()) {
result = null;
} else {
result = new LoadPath<>(dataClass, resourceClass, transcodeClass, decodePaths,
exceptionListPool);
}
loadPathCache.put(dataClass, resourceClass, transcodeClass, result);
}
return result;
}
private List> getDecodePaths(
Class dataClass, Class resourceClass, Class transcodeClass) {
List> decodePaths = new ArrayList<>();
List> registeredResourceClasses =
decoderRegistry.getResourceClasses(dataClass, resourceClass);
for (Class registeredResourceClass : registeredResourceClasses) {
List> registeredTranscodeClasses =
transcoderRegistry.getTranscodeClasses(registeredResourceClass, transcodeClass);
for (Class registeredTranscodeClass : registeredTranscodeClasses) {
List> decoders =
decoderRegistry.getDecoders(dataClass, registeredResourceClass);
ResourceTranscoder transcoder =
transcoderRegistry.get(registeredResourceClass, registeredTranscodeClass);
decodePaths.add(new DecodePath<>(dataClass, registeredResourceClass,
registeredTranscodeClass, decoders, transcoder, exceptionListPool));
}
}
return decodePaths;
}
public List> getRegisteredResourceClasses(
Class modelClass, Class resourceClass, Class transcodeClass) {
List> result = modelToResourceClassCache.get(modelClass, resourceClass);
if (result == null) {
result = new ArrayList<>();
List> dataClasses = modelLoaderRegistry.getDataClasses(modelClass);
for (Class> dataClass : dataClasses) {
List extends Class>> registeredResourceClasses =
decoderRegistry.getResourceClasses(dataClass, resourceClass);
for (Class> registeredResourceClass : registeredResourceClasses) {
List> registeredTranscodeClasses = transcoderRegistry
.getTranscodeClasses(registeredResourceClass, transcodeClass);
if (!registeredTranscodeClasses.isEmpty() && !result.contains(registeredResourceClass)) {
result.add(registeredResourceClass);
}
}
}
modelToResourceClassCache.put(modelClass, resourceClass,
Collections.unmodifiableList(result));
}
return result;
}
public boolean isResourceEncoderAvailable(Resource> resource) {
return resourceEncoderRegistry.get(resource.getResourceClass()) != null;
}
public ResourceEncoder getResultEncoder(Resource resource)
throws NoResultEncoderAvailableException {
ResourceEncoder resourceEncoder = resourceEncoderRegistry.get(resource.getResourceClass());
if (resourceEncoder != null) {
return resourceEncoder;
}
throw new NoResultEncoderAvailableException(resource.getResourceClass());
}
@SuppressWarnings("unchecked")
public Encoder getSourceEncoder(X data) throws NoSourceEncoderAvailableException {
Encoder encoder = encoderRegistry.getEncoder((Class) data.getClass());
if (encoder != null) {
return encoder;
}
throw new NoSourceEncoderAvailableException(data.getClass());
}
public DataRewinder getRewinder(X data) {
return dataRewinderRegistry.build(data);
}
public List> getModelLoaders(Model model) {
List> result = modelLoaderRegistry.getModelLoaders(model);
if (result.isEmpty()) {
throw new NoModelLoaderAvailableException(model);
}
return result;
}
public List getImageHeaderParsers() {
List result = imageHeaderParserRegistry.getParsers();
if (result.isEmpty()) {
throw new NoImageHeaderParserException();
}
return result;
}
/**
* Thrown when no {@link com.bumptech.glide.load.model.ModelLoader} is registered for a given
* model class.
*/
public static class NoModelLoaderAvailableException extends MissingComponentException {
public NoModelLoaderAvailableException(Object model) {
super("Failed to find any ModelLoaders for model: " + model);
}
public NoModelLoaderAvailableException(Class> modelClass, Class> dataClass) {
super("Failed to find any ModelLoaders for model: " + modelClass + " and data: " + dataClass);
}
}
/**
* Thrown when no {@link ResourceEncoder} is registered for a given resource class.
*/
public static class NoResultEncoderAvailableException extends MissingComponentException {
public NoResultEncoderAvailableException(Class> resourceClass) {
super("Failed to find result encoder for resource class: " + resourceClass);
}
}
/**
* Thrown when no {@link Encoder} is registered for a given data class.
*/
public static class NoSourceEncoderAvailableException extends MissingComponentException {
public NoSourceEncoderAvailableException(Class> dataClass) {
super("Failed to find source encoder for data class: " + dataClass);
}
}
/**
* Thrown when some necessary component is missing for a load.
*/
public static class MissingComponentException extends RuntimeException {
public MissingComponentException(String message) {
super(message);
}
}
/**
* Thrown when no {@link ImageHeaderParser} is registered.
*/
public static final class NoImageHeaderParserException extends MissingComponentException {
public NoImageHeaderParserException() {
super("Failed to find image header parser.");
}
}
}