Migrating from v3 to v4
Options
One of the larger changes in Glide v4 is the way the library handles options (centerCrop()
, placeholder()
etc). In Glide v3, options were handled individually by a series of complicated multityped builders. In Glide v4 these have been replaced by a single builder with a single type and a series of options objects that can be provided to the builder. Glide’s generated API simplifies this further by merging options from the options objects and from any included integration libraries with the builder to create a single fluent API.
RequestBuilder
Includes methods like:
listener()
thumbnail()
load()
into()
In Glide v4 there is only a single RequestBuilder
with a single type that indicates the type of item you’re attempting to load (Bitmap
, Drawable
, GifDrawable
etc). The RequestBuilder
provides direct access to options that affect the load process itself, including the model (url, uri etc) you want to load, any thumbnail()
requests and any RequestListener
s. The RequestBuilder
also is the place where you start the load using into()
or preload()
:
RequestBuilder<Drawable> requestBuilder = Glide.with(fragment)
.load(url);
requestBuilder
.thumbnail(Glide.with(fragment)
.load(thumbnailUrl))
.listener(requestListener)
.load(url)
.into(imageView);
RequestOptions
Includes methods like:
centerCrop()
placeholder()
error()
priority()
diskCacheStrategy()
Most options have moved into a separate object called RequestOptions
:
RequestOptions options = new RequestOptions()
.centerCrop()
.placeholder(R.drawable.placeholder)
.error(R.drawable.error)
.priority(Priority.HIGH);
RequestOptions
are applied to RequestBuilders
to allow you to specify a set of options once and then use them for multiple loads:
RequestOptions myOptions = new RequestOptions()
.fitCenter()
.override(100, 100);
Glide.with(fragment)
.load(url)
.apply(myOptions)
.into(drawableView);
Glide.with(fragment)
.asBitmap()
.apply(myOptions)
.load(url)
.into(bitmapView);
Transformations
Transformations
in Glide v4 now replace any previously set transformations. If you want to apply more than one Transformation
in Glide v4, use the transforms()
method:
Glide.with(fragment)
.load(url)
.apply(new RequestOptions().transforms(new CenterCrop(), new RoundedCorners(20)))
.into(target);
Or with the generated API:
GlideApp.with(fragment)
.load(url)
.transforms(new CenterCrop(), new RoundedCorners(20))
.into(target);
DecodeFormat
In Glide v3, the default DecodeFormat
was DecodeFormat.PREFER_RGB_565
, which used Bitmap.Config.RGB_565
unless the image contained or might have contained transparent pixels. RGB_565
uses half the memory of Bitmap.Config.ARGB_8888
for a given image size, but it has noticeable quality issues for certain images, including banding and tinting. To avoid the quality issues with RGB_565
, Glide defaults to ARGB_8888
. As a result, image quality is higher, but memory usage may increase.
To change Glide’s default DecodeFormat
back to DecodeFormat.PREFER_RGB_565
in Glide v4, apply the RequestOption
in an AppGlideModule
:
@GlideModule
public final class YourAppGlideModule extends GlideModule {
@Override
public void applyOptions(Context context, GlideBuilder builder) {
builder.setDefaultRequestOptions(new RequestOptions().format(DecodeFormat.PREFER_RGB_565));
}
}
For more on using AppGlideModules
, see the configuration page. Note that you will have to make sure to add a dependency on Glide’s annotation processor to ensure that Glide picks up your AppGlideModule
implementation. For more information on how to set up the library, see the download and setup page.
TransitionOptions
Includes methods like:
crossFade()
animate()
Options that control cross fades and other transitions from placeholders to images and/or between thumbnails and the full image have been moved into TransitionOptions
.
To apply transitions (formerly animations), use one of the transition options that matches the type of resource you’re requesting:
To remove any default transition, use TransitionOptions.dontTransition()
.
Transitions are applied to a request using RequestBuilder
:
Glide.with(fragment)
.load(url)
.transition(withCrossFade(R.anim.fade_in, 300));
Cross fades.
Unlike Glide v3, Glide v4 does NOT apply a cross fade or any other transition by default to requests. Transitions must be applied manually.
To apply a cross fade transition to a particular load, you can use:
import static com.bumptech.glide.load.resource.drawable.DrawableTransitionOptions.withCrossFade;
Glide.with(fragment)
.load(url)
.transition(withCrossFade())
.into(imageView);
Or:
Glide.with(fragment)
.load(url)
.transition(
new DrawableTransitionOptions
.crossFade())
.into(imageView);
Generated API
To make it even easier to use Glide v4, Glide now also offers a generated API for Applications. Applications can access the generated API by including an appropriately annotated AppGlideModule
implementation. See the Generated API page for details on how this works.
The generated API adds a GlideApp
class, that provides access to RequestBuilder
and RequestOptions
subclasses. The RequestOptions
subclass contains all methods in RequestOptions
and any methods defined in GlideExtensions
. The RequestBuilder
subclass provides access to all methods in the generated RequestOptions
subclass without having to use apply
:
A request without the generated API might look like this:
Glide.with(fragment)
.load(url)
.apply(centerCropTransform()
.placeholder(R.drawable.placeholder)
.error(R.drawable.error)
.priority(Priority.HIGH))
.into(imageView);
With the generated API, the RequestOptions
calls can be inlined:
GlideApp.with(fragment)
.load(url)
.centerCrop()
.placeholder(R.drawable.placeholder)
.error(R.drawable.error)
.priority(Priority.HIGH)
.into(imageView);
You can still use the generated RequestOptions
subclass to apply the same set of options to multiple loads, but generated RequestBuilder
subclass may be more convenient in most cases.
Types and Targets
Picking Resource Types
Glide allows you to specify what type of resource you want to load. If you specify a super type, Glide will attempt to load any available subtypes. For example, if you request a Drawable, Glide may load either a BitmapDrawable or a GifDrawable. If you request a GifDrawable, Glide will either load a GifDrawable or error if the image isn’t a GIF (even if it happens to be a perfectly valid image).
Drawables are requested by default:
Glide.with(fragment).load(url)
To request a Bitmap:
Glide.with(fragment).asBitmap()
To obtain a filepath (best for local images):
Glide.with(fragment).asFile()
To download a remote file into cache and obtain a file path:
Glide.with(fragment).downloadOnly()
// or if you have the url already:
Glide.with(fragment).download(url);
Drawables
GlideDrawable
in Glide v3 has been removed in favor of the standard Android Drawable
. GlideBitmapDrawable
has been removed in favor of BitmapDrawable
.
If you want to know if a Drawable is animated, you can check if it is an instance of Animatable
:
boolean isAnimated = drawable instanceof Animatable
Targets
The signature of onResourceReady
has changed. For example, for Drawables
:
onResourceReady(GlideDrawable drawable, GlideAnimation<? super GlideDrawable> anim)
is now:
onResourceReady(Drawable drawable, Transition<? super Drawable> transition);
Similarly the signature of onLoadFailed
has also changed:
onLoadFailed(Exception e, Drawable errorDrawable)
is now:
onLoadFailed(Drawable errorDrawable)
If you need more information about the errors that caused the load to fail, you can use RequestListener
.
Cancellation
Glide.clear(Target)
has moved into RequestManager
:
Glide.with(fragment).clear(target)
Although it’s not required, it’s most performant to use the RequestManager
that started the load to also clear the load. Glide v4 keeps track of requests per Activity and Fragment so clearing needs to remove the request at the appropriate level.
Configuration
In Glide v3, configuration is performed via one or more GlideModules
. In Glide v4, configuration is done via a similar but slightly more sophisticated system.
For details on the new system, see the Configuration page.
Applications
Applications that have a single GlideModule
can convert their GlideModule
into a AppGlideModule
.
In Glide v3, you might have a GlideModule
like this:
public class GiphyGlideModule implements GlideModule {
@Override
public void applyOptions(Context context, GlideBuilder builder) {
builder.setMemoryCache(new LruResourceCache(10 * 1024 * 1024));
}
@Override
public void registerComponents(Context context, Glide glide) {
glide.register(Api.GifResult.class, InputStream.class, new GiphyModelLoader.Factory());
}
}
In Glide v4, you would convert it into a AppGlideModule
that looks like this:
@GlideModule
public class GiphyGlideModule extends AppGlideModule {
@Override
public void applyOptions(Context context, GlideBuilder builder) {
builder.setMemoryCache(new LruResourceCache(10 * 1024 * 1024));
}
@Override
public void registerComponents(Context context, Glide glide, Registry registry) {
registry.append(Api.GifResult.class, InputStream.class, new GiphyModelLoader.Factory());
}
}
Note that the @GlideModule
annotation is required.
If your application has multiple GlideModule
s, convert one of them to a AppGlideModule
and the others to LibraryGlideModule
s. LibraryGlideModule
s will not be discovered unless a AppGlideModule
is present, so you cannot use only LibraryGlideModule
s.
Libraries
Libraries that have one or more GlideModule
s should use LibraryGlideModule
instead of AppGlideModule
. Libraries should not use AppGlideModule
s because there can only be one per Application, so including it in a library would not only prevent users of the library from setting their own options, but it would also cause conflicts if multiple libraries included a AppGlideModule
.
For example, the Volley GlideModule
in v3:
public class VolleyGlideModule implements GlideModule {
@Override
public void applyOptions(Context context, GlideBuilder builder) {
// Do nothing.
}
@Override
public void registerComponents(Context context, Glide glide) {
glide.register(GlideUrl.class, InputStream.class, new VolleyUrlLoader.Factory(context));
}
}
Can be converted to a LibraryGlideModule
in v4:
@GlideModule
public class VolleyLibraryGlideModule extends LibraryGlideModule {
@Override
public void registerComponents(Context context, Glide glide, Registry registry) {
registry.replace(GlideUrl.class, InputStream.class, new VolleyUrlLoader.Factory(context));
}
}
Manifest parsing
To ease the migration, manifest parsing and the older GlideModule
interface are deprecated, but still supported in v4. AppGlideModule
s, LibraryGlideModule
s and the deprecated GlideModule
s can all coexist in an application.
However, to avoid the performance overhead of checking metadata (and associated bugs), you can disable manifest parsing once your migration is complete by overriding a method in your AppGlideModule
:
@GlideModule
public class GiphyGlideModule extends AppGlideModule {
@Override
public boolean isManifestParsingEnabled() {
return false;
}
...
}
using()
, ModelLoader, StreamModelLoader.
ModelLoader
The ModelLoader
API exists in Glide v4 and serves the same purpose that it did in Glide v3, but a few of the specifics have changed.
First specific subtypes of ModelLoader
, like StreamModelLoader
are now unnecessary and users can implement ModelLoader
directly. For example, a StreamModelLoader<File>
would now be implemented and referred to as a ModelLoader<File, InputStream>
.
Second, instead of returning a DataFetcher
directly, ModelLoader
s now return LoadData
. LoadData
is a very simple wrapper that contains a disk cache key and a DataFetcher
.
Third, ModelLoaders
have a handles()
method, so that you can register more than one ModelLoader with the same type parameters.
Converting a ModelLoader
from the v3 API to the v4 API is almost always straight forward. If you just return a DataFetcher
in your v3 ModelLoader
:
public final class MyModelLoader implements StreamModelLoader<File> {
@Override
public DataFetcher<InputStream> getResourceFetcher(File model, int width, int height) {
return new MyDataFetcher(model);
}
}
Then all you need to do in your v4 equivalent is wrap the data fetcher:
public final class MyModelLoader implements ModelLoader<File, InputStream> {
@Override
public LoadData<InputStream> buildLoadData(File model, int width, int height,
Options options) {
return new LoadData<>(model, new MyDataFetcher(model));
}
@Override
public void handles(File model) {
return true;
}
}
Note that the model is passed in to the LoadData
to act as part of the cache key, in addition to the DataFetcher
. This pattern provides more control over the disk cache key in some specialized circumstances. Most implementations can just pass their model directly into LoadData
as is done above. For this to work correctly your model needs to correctly implements hashCode()
and equals()
If you’d only like to use your ModelLoader for some models you can use the handles()
method to inspect the model before you try to load it. If you return false
from handles()
your ModelLoader
will not be to load the given model, even if the types of your ModelLoader
(File
and InputStream
in this example) match.
For example, if you’re writing encrypted images to disk in a specific folder, you could use the handles()
method to implement a ModelLoader
that decrypted images from that specific folder but wasn’t used when loading File
s from other folders:
public final class MyModelLoader implements ModelLoader<File, InputStream> {
private static final String ENCRYPTED_PATH = "/my/encrypted/folder";
@Override
public LoadData<InputStream> buildLoadData(File model, int width, int height,
Options options) {
return new LoadData<>(model, new MyDataFetcher(model));
}
@Override
public void handles(File model) {
return model.getAbsolutePath().startsWith(ENCRYPTED_PATH);
}
}
using()
The using()
API was removed in Glide 4 to encourage users to register their components once with a AppGlideModule
to avoid object re-use. Rather than creating a new ModelLoader
each time you load an image, you register it once in an AppGlideModule
and let Glide inspect your model (the object you pass to load()
) to figure out when to use your registered ModelLoader
.
To make sure you only use your ModelLoader
for certain models, implement handles()
as shown above to inspect each model and return true only if your ModelLoader
should be used.