この記事ではGlide 4.0.0 RC1を使用しています。
Glide 4.0.0の正式リリースの際には仕様が変更される場合がありますので、ご注意ください。
Glide 4.2.0での動作を確認していますが、今後の仕様変更にはご注意ください。
はじめに
5月18日にGlide 4.0.0のプレリリース版である、Glide 4.0.0 RC0がリリースされました。
そして、先日6月21日にはRC1がリリースされています。
8月2日にGlide 4.0.0が、9月2日にGlide 4.1.0が、10月4日にGlide 4.2.0がリリースされています。
@ryugooさんが「画像読み込みライブラリ Glide の v4 を試してみる」というGlide v4に関する記事を書いて下さっていますが、実際に試してみたところほかにもTipsがいくつか見つかったので、ここにまとめておこうと思います。
Glide v4の導入の仕方などはこの記事では紹介しませんので、先ほど紹介した@ryugooさんの記事を参考にしてみてください。
サンプルプロジェクト
Glide v3とv4のそれぞれを使用したサンプルアプリを作成したので、ぜひ併せて使ってみてください。
モジュールを切り替えることで、v3とv4を切り替えられるようになっています。また、アプリ内でも簡単にコードを見れるようにしていますので、活用してもらえると嬉しいです。
この記事で紹介する内容以外のことも実装しているので、Glideの入門にも使えるかと思います。
このサンプルプロジェクトおよび、記事内ではKotlinを主に使用しています。
追記
サンプルプロジェクト内にGlide 4.2.0対応を行ったモジュールを追加しました。
基本的な使い方
先ほど紹介した「画像読み込みライブラリ Glide の v4 を試してみる」の中でも紹介されていますが、v3とv4の大きな違いは、Glideに加えてGlideAppというクラスを使用できるようになったことです。
v3においては
Glide.with(context)
.load(imageUrl)
.centerCrop()
.placeholder(R.drawable.placeholder)
.error(R.drawable.error)
.into(targetImageView)
という様にGlide.with()に続けてオプションを指定することができましたが、v4においてはGlide.with()に続けて指定できるオプションは限られています。
v4ではRequestOptionsを使用してその他のオプションを指定します。
val options = RequestOptions()
.centerCrop()
.placeholder(R.drawable.placeholder)
.error(R.drawable.error)
Glide.with(context)
.load(imageUrl)
.apply(options)
.into(targetImageView)
ただ、複数のtargetに対して同じオプションを適用する場合には便利ですが、targetが単体だったり、複数のtargetに異なるオプションを適用する場合には、なんだか不便な様にも思えます。
そこで、GlideAppというクラスを使用します。このクラスはv4の大きな特徴と言えるannotation processingで生成されるクラスです。こちらを使用するとv3の時と同様に
GlideApp.with(context)
.load(imageUrl)
.centerCrop()
.placeholder(R.drawable.placeholder)
.error(R.drawable.error)
.into(targetImageView)
といった具合に続けて書くことができます。
この記事やサンプルプロジェクト内ではGlideAppを使用する形に統一しています。
Resource Typeの指定
Glideを使用すると簡単に指定した形式で画像を読み込むことが可能です。
例えば、v3では
Glide.with(context)
.load(imageUrl)
.asBitmap()
...
Glide.with(context)
.load(imageUrl)
.asGif()
...
とすればよかったですね。
しかし、v4においてはこのasXxx()を指定する場所が変わりました。形式の指定はwith()の後に記述しなければなりません。
つまり
GlideApp.with(context)
.asBitmap()
.load(imageUrl)
...
GlideApp.with(context)
.asGif()
.load(imageUrl)
...
といった具合に記述する必要があります。
これはGlide v4において、読み込みの形式をより柔軟に指定することが可能になった影響だと考えられます。ライブラリ内で用意されている
- asDrwable
- asBitmap
- asGif
- asFile
以外にも、.as()を使用することで、任意の形式に変換することが可能になりました。
読み込みのキャンセル
Glideは画像の読み込み、またはキャンセルをよしなにハンドリングしてくれますが、任意のタイミングでキャンセルを行いたいという場合も出てきます。
v3においては
Glide.clear(tragetImageView)
でよかったのですが、v4では
GlideApp.with(context)
.clear(targetImageView)
とwith()の後に呼ばなければいけなくなりました。
v4では画像のリクエストをActivityやFragment単位で保持するようになったためです。
そのため、clear()を行う際にはwith()で指定したContextのライフサイクルに注意しておく必要がありそうです。
Diskへのキャッシュ
GlideはmemoryやDiskへ一度読み込んだ画像をキャッシュしてくれます。これによって、再表示する際にわざわざもう一度画像リソースの全てを読み込む必要がなくなり、画像をより早く表示することが可能です。
キャッシュ先はmemoryとDiskの2つがありますが、GlideではどのレベルまでリソースをDiskにキャッシュするか指定することができます。
まずv3の方からおさらいしましょう。
-
DiskCacheStrategy.NONE- 何もキャッシュしない
-
DiskCacheStrategy.SOURCE- オリジナルの解像度のデータだけキャッシュ
-
DiskCacheStrategy.RESULT(default)- 解像度を落としたtarget内に表示されるリソースのみをキャッシュ
-
DiskCacheStrategy.ALL- 全ての解像度のリソースをキャッシュ
これに対し、v4では次のように変更されました。
-
DiskCacheStrategy.NONE- 何もキャッシュしない
-
DiskCacheStrategy.DATA- デコード前に回収されたデータをキャッシュ
-
DiskCacheStrategy.RESOURCE- デコードされたリソースをキャッシュ
-
DiskCacheStrategy.ALL- 読み込む画像がローカルにある場合は、デコードされた後のリソースをキャッシュ
- 読み込む画像がリモートにある場合は、デコードされたリソースとデコード前に回収されたデータをキャッシュ
-
DiskCacheStrategy.AUTOMATIC(default)- 状況に合わせて、キャッシュの方法を決定する
ここでデータとリソースという言葉を使い分けていますが、データというのが画像を取ってくる前のあらゆるデータ、リソースというのが画像を取得した後の必要な部分だけのデータだと考えてもらえると分かりやすいかと思います。
JavaDocsには、ほとんどの場合にはRESOURCEを使用するのが理想的だと書いてあります。しかし、同じリソースを何度も表示したり様々なサイズで表示したりするアプリや、通信状況の悪い場合を考慮したいアプリなどはDATAやALLを試してみると良いようです。
Gifの読み込みにRESOURCEを使用した例です。

読み込みが非常にスムーズですね!
Transformations
Glideを使用することにより、表示する画像を加工することができます。
またGlide Transformationsという有名なライブラリを使用することで、さらに多くのTransformationを簡単に実現することが可能です。もちろんTransformationインタフェースを自分で実装してオリジナルのTransformationを作成することも可能です。
Circle Crop
そんな便利なTransformationですが、v3のGlideライブラリ自身には.centerCrop()と.fitCenter()の2つのオプションしか含まれていませんでした。
Glide.with(context)
.load(urlString)
.centerCrop()
// .fitCenter() // fitCenterを指定
// .bitmapTransform(CustomTransformation) // カスタムTransformation
...
このように使用できますね。
v4では何が変わったかというと、この2つに加えて.circleCrop()が登場しました。これはその名の通り、画像を円形に切り取ってくれます。
v4でもこれらの使い方は変わりません。
GlideApp.with(context)
.load(urlString)
.circleCrop()
// .centerCrop() // centerCropを指定
// .fitCenter() // fitCenterを指定
// .transform(CustomTransformation) // カスタムTransformation
...
Multi Transformations
先ほども紹介したGlide Transformationsを見てみると、多くのTransformationがあることが分かります。「あれとこれを一緒に使えたら良いのになあ」なんて思っちゃいますよね?
そう、Glideなら簡単にできちゃうんです!!
実はこれv3の頃からできるんですが、v4ではちょっぴり使い方が変わりました。
Glide.with(context)
.load(urlString)
.bitmapTransform(GrayscaleTransformation(context), BlurTransformation(context, 10))
...
GlideApp.with(context)
.load(urlString)
.transform(MultiTransformation(GrayscaleTransformation(), BlurTransformation(10)))
...
コードを見てお気づきだと思いますが、v4では複数のTransformationを指定する際にはMultiTransformationクラスのインスタンスを.transform()に渡してあげる必要があります。
ちょっと不便になったなあと感じる方もいるかもしれませんが、その代わりに(と言ってはなんですが)、Transformationインタフェースのtransformメソッドの引数にContextが加わったことにより、カスタムTransformationのコンストラクタでContextを渡さなくてもよくなりました!
結局記述量はそれほど変わらないですね 笑
追記
Glide 4.1.0で、Multiple Transformationsのshortcutが追加されました。
具体的には以下のように記述します。
GlideApp.with(context)
.load(urlString)
.transforms(GrayscaleTransformation(), BlurTransformation(10))
...
v3の時のように記述できるようになりました!!
Custom Transformation
先ほども少し触れましたが、独自のTransformationを作成するにはTransformationインタフェースを実装したクラスを作成する必要があります。
このTransformationインタフェースですが、v3とv4で大きく分けて2つの変更が加わりました。
-
transformメソッドの引数にContextが加わった -
getId()メソッドの代わりにupdateDiskCacheKey(MessageDigest messageDigest)を実装しなければならなくなった
これらの変更により、先ほどから紹介しているGlide TransformationsをGlide v4で使用するには、使用したいカスタムTransformationを自分でv4でのTransformationに適応させる必要があります。
ここでは詳しい解説はしませんが、サンプルアプリ内ではv4用に適応させたTransformationがいくつかあるので参考にしてみてください。
Glide Transformationsの方もおそらくGlide v4の正式リリースに合わせてv4向けに修正されるのではないでしょうか。
Transition
Glideを使用することで、表示する画像とplaceholderをクロスフェードさせたり、画像の表示アニメーションを設定することが可能になります。
v3とv4ではTransition周りに多くの変更が加わりました。これまでv3に慣れ親しんだ方はv4を使ってみて結構困惑するかもしれません。
Cross Fade
まず一つ目の大きな変更は、v3ではplaceholderと表示する画像のクロスフェードがデフォルトでONになっていましたが、v4ではデフォルトのクロスフェードはOFFになりました。
v4でクロスフェードをONにするには、次のように記述します。
GlideApp.with(context)
.load(imageString)
.placeholder(R.drawable.image_placeholder)
.transition(DrawableTransitionOptions.withCrossFade())
...
.transition()の引数にDrawableTransitionOptions#withCrossFade()を設定する必要があります。asBitmap()を使用してBitmap形式に変換している場合はBitmapTransitionOptions#withCrossFade()を使用すれば良いです。
クロスフェードのアニメーションにかかる時間を変更したい場合は
GlideApp.with(context)
.load(imageString)
.placeholder(R.drawable.image_placeholder)
.transition(DrawableTransitionOptions.withCrossFade(1000)) // default is 300
...
という風にwithCrossFade()の引数にミリ秒で時間を指定します。
追記
Glide 4.1.0でdefaultのTransitionsを設定できるようになりました。
設定はAppGlideModuleを継承しているクラスで行います。
defaultでCross Fadeをオンにしたい場合には
override fun applyOptions(context: Context, builder: GlideBuilder) {
builder.setDefaultTransitionOptions(Drawable::class.java, DrawableTransitionOptions.withCrossFade())
.setDefaultTransitionOptions(Bitmap::class.java, BitmapTransitionOptions.withCrossFade())
}
というように記述します。
また、defaultのCross Fadeはオンにしたいけど、一部ではオフにしたいという場合には、
GlideApp.with(context)
.load(imageString)
.placeholder(R.drawable.image_placeholder)
.transition(GenericTransitionOptions.withNoTransition())
...
として、GenericTransitionOptions#withNoTransitionを使用すれば良いです。
Animation
Glideではクロスフェード以外にもスライドインやズームインなど、様々なアニメーションを画像の表示時に指定することが可能です。
Glide v3では.animate()の引数にアニメーションを指定することで実現可能でした。
しかし、v4においてはクロスフェードの時と同様に.transition()を使用してアニメーションを指定するように変更されました。
例えば次のようなズームインアニメーションを指定したい場合には
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:fillAfter="true">
<scale
android:duration="@android:integer/config_longAnimTime"
android:fromXScale="0.1"
android:fromYScale="0.1"
android:pivotX="50%"
android:pivotY="50%"
android:toXScale="1"
android:toYScale="1" />
</set>
GlideApp.with(context)
.load(imageString)
.placeholder(R.drawable.image_placeholder)
.transition(DrawableTransitionOptions().transition(R.anim.zoom_in))
...
という風に指定しなければいけません。
クロスフェードの時との違いは、DrawableTransitionOptionsクラスをインスタンス化し、そのtransitionメソッドにアニメーションを指定するという点です。
クロスフェードの時と同様、asBitmap()を指定している場合にはBitmapTransitionOptionsクラスに置き換えてください。
また、xmlでのanimation以外にもViewPropertyTransition#Animatorインタフェースを実装したアニメーションを引数に指定することも可能です。
Transitionのまとめ
上で2つのアニメーションの方法を見て気づいた方もいると思いますが、v3における.crossFade()オプションと.animate()オプションは、v4において.transition()オプションに集約されました。
v3とv4でのそれぞれのオプションの対応は次のようになると考えてもらえると良いと思います。
| v3 | v4 |
|---|---|
.crossFade() |
.transition(DrawableTransitionOptions.withCrossFade()) |
.animate(animate) |
.transition(DrawableTransitionOptions().transition(animate)) |
例外的なTransition
いつくかのパターンにおいて上で紹介した方法ではtransitionが期待した動作をしてくれない場合があるので、そちらも紹介しておきます。
特殊なImageView
CircleImageViewやShapeImageViewといったImageViewの一部がクロップされているImageViewに対して、.placeholder()や.thumbnail()で指定した画像とクロスフェードさせようとした場合、読み込んだ画像がそのImageViewの形にクロップされずに表示されてしまいます。
実装は次の通りです。
GlideApp.with(this)
.load(photoList[0].getPhotoUrl())
.placeholder(R.drawable.image_placeholder)
.circleCrop()
.transition(DrawableTransitionOptions.withCrossFade())
.into(circleImageView)
GlideApp.with(this)
.load(photoList[1].getPhotoUrl())
.placeholder(R.drawable.image_placeholder)
.transition(DrawableTransitionOptions.withCrossFade())
.into(diamondImageView)
この問題はGlide v3から残っている問題で、v4でも発生します。
対処方法がいくつかあるので、紹介します。
- クロスフェードさせない
- そもそもクロスフェードが原因なので
.dontAnimate()を使用して、クロスフェードをさせなければ問題はないです
- そもそもクロスフェードが原因なので
-
.circleCrop()を使用- 円形のImageViewの場合はImageViewをクロップするのではなく、表示する画像を
.circleCrop()を使用して円形にクロップしてあげれば、良いです。ただし、クロスフェードも効きませんし、placeholder()で指定した画像まではクロップされません。
- 円形のImageViewの場合はImageViewをクロップするのではなく、表示する画像を
- animationを指定する
-
.transition(DrawableTransitionOptions().transition(animate))のanimateにフェードインのアニメーションを指定してあげることで、厳密には.placeholder()で表示した画像とのクロスフェードとまではいきませんが、それっぽく表示することが可能です。
-
どうしても一部のImageViewがクロップされているImageViewに対して、どうしてもクロスフェードをかけたいという場合には3の方法で妥協するしかないようです。
実装は次の通りです。
GlideApp.with(this)
.load(photoList[0].getPhotoUrl())
.placeholder(R.drawable.image_placeholder)
.transition(DrawableTransitionOptions().transition(android.R.anim.fade_in))
.into(circleImageView)
GlideApp.with(this)
.load(photoList[1].getPhotoUrl())
.placeholder(R.drawable.image_placeholder)
.transition(DrawableTransitionOptions().transition((android.R.anim.fade_in)))
.into(diamondImageView)
また、補足として、v3において3の方法を使用する場合には.asBitmap()でBitmapに変換した後に.animateでanimationを指定する必要がありましたが、v4ではBitmapに変換する必要はなくなったようです。
特殊な画像の読み込み
読み込む画像の一部が透明であったり、読み込む画像がplaceholderとして表示する画像のサイズよりも小さい場合にクロスフェードを指定すると、読み込んだ画像の後ろにplaceholderとして表示した画像が残ってしまうという現象が起きます。
この現象はv3では起こりませんが、v4では発生してしまいます。
この方法を解決するにはちょっと特殊な方法でCrossFadeをオンにする必要があります。
先ほども紹介しましたが、一般的な画像に対してクロスフェードをかけたい場合には
GlideApp.with(context)
.load(imageString)
.placeholder(R.drawable.image_placeholder)
.transition(DrawableTransitionOptions.withCrossFade())
...
でクロスフェードをオンにする必要がありました。
しかし、この特殊な場合には
GlideApp.with(context)
.load(imageString)
.placeholder(R.drawable.image_placeholder)
.transition(DrawableTransitionOptions().crossFade(
DrawableCrossFadeFactory.Builder()
.setCrossFadeEnabled(true)
.build()
))
// or
// .transition(DrawableTransitionOptions().transition(android.R.anim.fade_in))
...
というように、明示的にクロスフェードを使用できるよう設定する必要があります。
また、厳密にはクロスフェードとは異なりますが、フェードインアニメーションを使用することで、似たような挙動を実現することも可能です。
おわりに
これまで見ていただいた通り、Glide v3とv4では変更点が多くあり、マイグレーションが必須となります。実際にマイグレーションをしてみて、つまづいた点を中心にまとめてみました。
この記事で紹介した変更点が全てではなく、他にもannotation processingを使用したGlideExtensionなど魅力的な変更もあります。
Glide 4.0.0の正式リリースももう間も無くかと思うので、(8月2日にGlide 4.0.0が、9月2日にGlide 4.1.0が、10月4日にGlide 4.2.0がリリースされています。)
ぜひ皆さんもお試しください!
間違いやもっといい方法あるよなどありましたら、コメントいただけると幸いです🙇
おまけ (Glide 4.1.0以降の主な変更点)
4.1.0 / 4.1.1
https://github.com/bumptech/glide/releases/tag/v4.1.0
https://github.com/bumptech/glide/releases/tag/v4.1.1
Features
- O以上で
Bitmap.Config.HARDWAREに対応 - Target APIが26に
- デフォルトのtransitionを設定可能に
- ネットワークリクエスト時のタイムアウトを設定可能に
-
trimMemory()やclearMemory()を明示的に呼ぶ必要がなくなった - 複数のTransfomationを使用するときに、
MultiTransformationを使用しなくてよくなった
API/Behavior changes
- cross fade transitionの実装がViewAnimationからTransitionDrawableに
- DecordeFormatを
DecodeFormat.ARGB_8888かDecodeFormat.RGB_565に設定している場合、Hardware Bitmapを使用するように
4.2.0
Features
- デフォルトの
Encorderを変更可能に - transcode時に
Optionを設定可能に
Behavior changes
- Viewサイズの計測方法が変更
4.3.0 / 4.3.1
https://github.com/bumptech/glide/releases/tag/v4.3.0
https://github.com/bumptech/glide/releases/tag/v4.3.1
Features
- external cache directoryが使用できない時にinternal cache directoryを使用する
DiskLruCacheFactoryが追加された - 最初の読み込みに失敗した際に、別の読み込みを開始できる
error()が追加 - bitmap drawableじゃないリソースのdecodeとtransformが可能に
- thumbnailのthumbnailみたいなものを設定したい時にネストが深くならないよう、
thumbnail()に複数のRequestBuilderを設定可能に - request自体にも
Contextを渡すようになり、Glide自身もそのContextのthemeを使用するように -
BitmapやDrawable自体をloadに渡すことが可能に
Behavior Changes
- gif画像を扱う際の品質とメモリ使用が向上
4.4.0
Features
-
Integer.MAX_VALUEよりも大きなサイズのキャッシュが可能に - Viewがdetachされた際にclearし、reattachされた際に処理を再開する
clearOnDetach()が追加 - Viewサイズを正しく計測するために、layoutされるまで待つ
waitForLayout()が追加
4.5.0
Features
- 全てのリクエストを一時停止するメソッドが利用可能に
- resource内の動画のデコードをサポート
Behavior Changes
- ライブラリの提供形式がデフォルトで
aarになったため、@aar指定は不要に - APIレベル 19未満を使用しているデバイスは
MemorySizeCaluculator.isLowMemoryDeviceでtrueが返されるように
Breaking Changes
-
@NonNull@Nullableアノテーションが追加されたため、コンパイラプラグインによってはビルドに失敗するかも
Build Changes
- CompileSdkVersionとTargetSdkVersionが27に
4.6.0 / 4.6.1
https://github.com/bumptech/glide/releases/tag/v4.6.0
https://github.com/bumptech/glide/releases/tag/v4.6.1
Breaking Changes
- 自動生成されるクラスなどに
@NonNull@Nullableアノテーションが追加
4.7.0 / 4.7.1
https://github.com/bumptech/glide/releases/tag/v4.7.0
https://github.com/bumptech/glide/releases/tag/v4.7.1
Features
- Uri形式のデータに対応
- スクロール時のパフォーマンスが向上
Behavior Changes
-
RecyclerViewやListViewでpreloaderを使用している場合、最初のスクロール前に次のページをpreloadするように
Breaking Changes
-
android.app.Fragmentの使用がdeprecatedに - depracatedだったtransformationのコンストラクタが削除された
4.8.0
Features
- 一つのリクエストに対して複数の
RequestListenerを設定可能に
Deprecations
-
SimpleTargetとViewTargetがdeprecatedに
Behavior Changes
-
RequestManagerによって一時停止されたリクエストが即座に一時停止されるようになり、placeholderの表示が可能に
Breaking Changes
-
pause()とisPaused()がRequestインタフェースから削除された
Build Changes
- annotation processerがAndroidXをサポート
4.9.0
Features
- 自動生成されるAPIを使用せずとも
RequestOptionをRequestBuilderに設定可能に - Global/Activity/Fragmentのスコープに対応した
RequestListenerが追加 - 不要なoverrideを可能な限りなくすために、
CustomTargetが追加 - dynamic moduleを使用しているresourceの読み込みをサポート
-
transforms()の代わりにtransform()の引数に複数のtransformationを追加できるように -
Animatable2Compatが追加されたことにより、無限ループしないGIFアニメーションの終了が検知できるように
Deprecations
-
transforms()がdepracatedに
Behavior Changes
- バックグラウンドでリクエストが開始された
RequestListenerのコールバックがバックグラウンドで呼ばれるように
Build Changes
- incremental annotation processingに対応
4.10.0
Features
-
GlideExecutorをmockするライブラリが追加 - Guavaの
ListenableFutureに対応したintegration libraryが追加 - 角丸の各角のradiusを変更できる
GranularRoundedCornersが追加 - resource isのcache keyがday/nightモードに対応
- メモリのクリアを手動で行えるAPIが追加
- wide gamut color spacesに対応
Build Changes
- TargetSdkVersionが28に
- AndroidXに対応
4.11.0
Features
- Glideの使用頻度が低いアプリケーションでメモリ使用を抑えるためにGlideのスレッドにtimeoutが設定できるように
- キャッシュ分析のためにBitmapPoolの情報が取得可能に
- デフォルト設定以外のDiskCacheStrategyを使っている場合でも、リモートの動画データからデコードが可能に
Bugs
- ExifInterfaceの警告ログが発生してしまう問題を修正








