Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
com.bumptech.glide.load.model.MultiModelLoaderFactory Maven / Gradle / Ivy
package com.bumptech.glide.load.model;
import android.support.annotation.Nullable;
import android.support.v4.util.Pools.Pool;
import com.bumptech.glide.Registry.NoModelLoaderAvailableException;
import com.bumptech.glide.load.Options;
import com.bumptech.glide.util.Preconditions;
import com.bumptech.glide.util.Synthetic;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
/**
* Capable of building an {@link ModelLoader} that wraps one or more other {@link ModelLoader}s for
* a given model and data class.
*/
public class MultiModelLoaderFactory {
private static final Factory DEFAULT_FACTORY = new Factory();
private static final ModelLoader EMPTY_MODEL_LOADER = new EmptyModelLoader();
private final List> entries = new ArrayList<>();
private final Factory factory;
private final Set> alreadyUsedEntries = new HashSet<>();
private final Pool> exceptionListPool;
public MultiModelLoaderFactory(Pool> exceptionListPool) {
this(exceptionListPool, DEFAULT_FACTORY);
}
// Visible for testing.
MultiModelLoaderFactory(Pool> exceptionListPool,
Factory factory) {
this.exceptionListPool = exceptionListPool;
this.factory = factory;
}
synchronized void append(Class modelClass, Class dataClass,
ModelLoaderFactory factory) {
add(modelClass, dataClass, factory, true /*append*/);
}
synchronized void prepend(Class modelClass, Class dataClass,
ModelLoaderFactory factory) {
add(modelClass, dataClass, factory, false /*append*/);
}
private void add(Class modelClass, Class dataClass,
ModelLoaderFactory factory, boolean append) {
Entry entry = new Entry<>(modelClass, dataClass, factory);
entries.add(append ? entries.size() : 0, entry);
}
synchronized List> replace(Class modelClass,
Class dataClass, ModelLoaderFactory factory) {
List> removed = remove(modelClass, dataClass);
append(modelClass, dataClass, factory);
return removed;
}
synchronized List> remove(Class modelClass,
Class dataClass) {
List> factories = new ArrayList<>();
for (Iterator> iterator = entries.iterator(); iterator.hasNext(); ) {
Entry, ?> entry = iterator.next();
if (entry.handles(modelClass, dataClass)) {
iterator.remove();
factories.add(this.getFactory(entry));
}
}
return factories;
}
synchronized List> build(Class modelClass) {
try {
List> loaders = new ArrayList<>();
for (Entry, ?> entry : entries) {
// Avoid stack overflow recursively creating model loaders by only creating loaders in
// recursive requests if they haven't been created earlier in the chain. For example:
// A Uri loader may translate to another model, which in turn may translate back to a Uri.
// The original Uri loader won't be provided to the intermediate model loader, although
// other Uri loaders will be.
if (alreadyUsedEntries.contains(entry)) {
continue;
}
if (entry.handles(modelClass)) {
alreadyUsedEntries.add(entry);
loaders.add(this.build(entry));
alreadyUsedEntries.remove(entry);
}
}
return loaders;
} catch (Throwable t) {
alreadyUsedEntries.clear();
throw t;
}
}
synchronized List> getDataClasses(Class> modelClass) {
List> result = new ArrayList<>();
for (Entry, ?> entry : entries) {
if (!result.contains(entry.dataClass) && entry.handles(modelClass)) {
result.add(entry.dataClass);
}
}
return result;
}
public synchronized ModelLoader build(Class modelClass,
Class dataClass) {
try {
List> loaders = new ArrayList<>();
boolean ignoredAnyEntries = false;
for (Entry, ?> entry : entries) {
// Avoid stack overflow recursively creating model loaders by only creating loaders in
// recursive requests if they haven't been created earlier in the chain. For example:
// A Uri loader may translate to another model, which in turn may translate back to a Uri.
// The original Uri loader won't be provided to the intermediate model loader, although
// other Uri loaders will be.
if (alreadyUsedEntries.contains(entry)) {
ignoredAnyEntries = true;
continue;
}
if (entry.handles(modelClass, dataClass)) {
alreadyUsedEntries.add(entry);
loaders.add(this.build(entry));
alreadyUsedEntries.remove(entry);
}
}
if (loaders.size() > 1) {
return factory.build(loaders, exceptionListPool);
} else if (loaders.size() == 1) {
return loaders.get(0);
} else {
// Avoid crashing if recursion results in no loaders available. The assertion is supposed to
// catch completely unhandled types, recursion may mean a subtype isn't handled somewhere
// down the stack, which is often ok.
if (ignoredAnyEntries) {
return emptyModelLoader();
} else {
throw new NoModelLoaderAvailableException(modelClass, dataClass);
}
}
} catch (Throwable t) {
alreadyUsedEntries.clear();
throw t;
}
}
@SuppressWarnings("unchecked")
private ModelLoaderFactory getFactory(Entry, ?> entry) {
return (ModelLoaderFactory) entry.factory;
}
@SuppressWarnings("unchecked")
private ModelLoader build(Entry, ?> entry) {
return (ModelLoader) Preconditions.checkNotNull(entry.factory.build(this));
}
@SuppressWarnings("unchecked")
private static ModelLoader emptyModelLoader() {
return (ModelLoader) EMPTY_MODEL_LOADER;
}
private static class Entry {
private final Class modelClass;
@Synthetic final Class dataClass;
@Synthetic final ModelLoaderFactory factory;
public Entry(Class modelClass, Class dataClass,
ModelLoaderFactory factory) {
this.modelClass = modelClass;
this.dataClass = dataClass;
this.factory = factory;
}
public boolean handles(Class> modelClass, Class> dataClass) {
return handles(modelClass) && this.dataClass.isAssignableFrom(dataClass);
}
public boolean handles(Class> modelClass) {
return this.modelClass.isAssignableFrom(modelClass);
}
}
static class Factory {
public MultiModelLoader build(
List> modelLoaders, Pool> exceptionListPool) {
return new MultiModelLoader<>(modelLoaders, exceptionListPool);
}
}
private static class EmptyModelLoader implements ModelLoader {
@Synthetic
EmptyModelLoader() { }
@Nullable
@Override
public LoadData buildLoadData(Object o, int width, int height, Options options) {
return null;
}
@Override
public boolean handles(Object o) {
return false;
}
}
}