Migrate Glide v3 to v4 ✈️

~~**この記事ではGlide 4.0.0 RC1を使用しています。**~~
~~Glide 4.0.0の正式リリースの際には仕様が変更される場合がありますので、ご注意ください。~~

[Glide 4.2.0](https://github.com/bumptech/glide/releases/tag/v4.2.0)での動作を確認していますが、今後の仕様変更にはご注意ください。

## はじめに
5月18日にGlide 4.0.0のプレリリース版である、Glide 4.0.0 RC0がリリースされました。
そして、先日6月21日にはRC1がリリースされています。
8月2日に[Glide 4.0.0](https://github.com/bumptech/glide/releases/tag/v4.0.0)が、9月2日に[Glide 4.1.0](https://github.com/bumptech/glide/releases/tag/v4.1.0)が、10月4日に[Glide 4.2.0](https://github.com/bumptech/glide/releases/tag/v4.2.0)がリリースされています。

@ryugooさんが「[画像読み込みライブラリ Glide の v4 を試してみる][try glide]」というGlide v4に関する記事を書いて下さっていますが、実際に試してみたところほかにもTipsがいくつか見つかったので、ここにまとめておこうと思います。
Glide v4の導入の仕方などはこの記事では紹介しませんので、先ほど紹介した@ryugooさんの記事を参考にしてみてください。

[try glide]: http://qiita.com/ryugoo/items/df3ff453897379cc1bd0

### サンプルプロジェクト
![](https://github.com/ronnnnn/GlideMigrationSample/blob/master/images/overview.gif?raw=true")

Glide v3とv4のそれぞれを使用した[サンプルアプリ][MGS]を作成したので、ぜひ併せて使ってみてください。
モジュールを切り替えることで、v3とv4を切り替えられるようになっています。また、アプリ内でも簡単にコードを見れるようにしていますので、活用してもらえると嬉しいです。
この記事で紹介する内容以外のことも実装しているので、Glideの入門にも使えるかと思います。

このサンプルプロジェクトおよび、記事内ではKotlinを主に使用しています。

[MGS]: https://github.com/ronnnnn/GlideMigrationSample

#### 追記
サンプルプロジェクト内に[Glide 4.2.0](https://github.com/bumptech/glide/releases/tag/v4.2.0)対応を行ったモジュールを追加しました。

## 基本的な使い方
先ほど紹介した「[画像読み込みライブラリ Glide の v4 を試してみる][try glide]」の中でも紹介されていますが、v3とv4の大きな違いは、`Glide`に加えて`GlideApp`というクラスを使用できるようになったことです。
v3においては

```kotlin:v3
Glide.with(context)
        .load(imageUrl)
        .centerCrop()
        .placeholder(R.drawable.placeholder)
        .error(R.drawable.error)
        .into(targetImageView)
```
という様に`Glide.with()`に続けてオプションを指定することができましたが、v4においては`Glide.with()`に続けて指定できるオプションは限られています。

v4では`RequestOptions`を使用してその他のオプションを指定します。

```kotlin:v4
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の時と同様に

```kotlin:v4
GlideApp.with(context)
        .load(imageUrl)
        .centerCrop()
        .placeholder(R.drawable.placeholder)
        .error(R.drawable.error)
        .into(targetImageView)
```
といった具合に続けて書くことができます。
この記事やサンプルプロジェクト内では`GlideApp`を使用する形に統一しています。

[try glide]: http://qiita.com/ryugoo/items/df3ff453897379cc1bd0

## Resource Typeの指定
Glideを使用すると簡単に指定した形式で画像を読み込むことが可能です。
例えば、v3では

```kotlin:v3
Glide.with(context)
        .load(imageUrl)
        .asBitmap()
        ...

Glide.with(context)
        .load(imageUrl)
        .asGif()
        ...
```
とすればよかったですね。
しかし、v4においてはこの`asXxx()`を指定する場所が変わりました。形式の指定は`with()`の後に記述しなければなりません。
つまり

```kotlin:v4
GlideApp.with(context)
        .asBitmap()
        .load(imageUrl)
        ...

GlideApp.with(context)
        .asGif()
        .load(imageUrl)
        ...
```
といった具合に記述する必要があります。
これはGlide v4において、読み込みの形式をより柔軟に指定することが可能になった影響だと考えられます。ライブラリ内で用意されている

- asDrwable
- asBitmap
- asGif
- asFile

以外にも、`.as()`を使用することで、任意の形式に変換することが可能になりました。

## 読み込みのキャンセル
Glideは画像の読み込み、またはキャンセルをよしなにハンドリングしてくれますが、任意のタイミングでキャンセルを行いたいという場合も出てきます。
v3においては

```kotlin:v3
Glide.clear(tragetImageView)
```
でよかったのですが、v4では

```kotlin: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][JavaDocs]には、ほとんどの場合には`RESOURCE`を使用するのが理想的だと書いてあります。しかし、同じリソースを何度も表示したり様々なサイズで表示したりするアプリや、通信状況の悪い場合を考慮したいアプリなどは`DATA`や`ALL`を試してみると良いようです。

Gifの読み込みに`RESOURCE`を使用した例です。
![](https://github.com/ronnnnn/GlideMigrationSample/blob/master/images/fast_gif.gif?raw=true)
読み込みが非常にスムーズですね！

[JavaDocs]: http://bumptech.github.io/glide/javadocs/400/com/bumptech/glide/request/RequestOptions.html#diskCacheStrategy-com.bumptech.glide.load.engine.DiskCacheStrategy-

## Transformations
Glideを使用することにより、表示する画像を加工することができます。
また[Glide Transformations][gt]という有名なライブラリを使用することで、さらに多くのTransformationを簡単に実現することが可能です。もちろん`Transformation`インタフェースを自分で実装してオリジナルのTransformationを作成することも可能です。

### Circle Crop
そんな便利な`Transformation`ですが、v3のGlideライブラリ自身には`.centerCrop()`と`.fitCenter()`の2つのオプションしか含まれていませんでした。

```kotlin:v3
Glide.with(context)
        .load(urlString)
        .centerCrop()
        // .fitCenter() // fitCenterを指定
        // .bitmapTransform(CustomTransformation) // カスタムTransformation
        ...
```

このように使用できますね。
v4では何が変わったかというと、この2つに加えて`.circleCrop()`が登場しました。これはその名の通り、画像を円形に切り取ってくれます。

![](https://github.com/ronnnnn/GlideMigrationSample/blob/master/images/circle_crop.gif?raw=true)

v4でもこれらの使い方は変わりません。

```kotlin:v4
GlideApp.with(context)
        .load(urlString)
        .circleCrop()
        // .centerCrop() // centerCropを指定
        // .fitCenter() // fitCenterを指定
        // .transform(CustomTransformation) // カスタムTransformation
        ...
```

### Multi Transformations
先ほども紹介した[Glide Transformations][gt]を見てみると、多くのTransformationがあることが分かります。「あれとこれを一緒に使えたら良いのになあ」なんて思っちゃいますよね？
そう、Glideなら簡単にできちゃうんです！！

![](https://github.com/ronnnnn/GlideMigrationSample/blob/master/images/multi_transform.gif?raw=true)

実はこれv3の頃からできるんですが、v4ではちょっぴり使い方が変わりました。

```kotlin:v3
Glide.with(context)
        .load(urlString)
        .bitmapTransform(GrayscaleTransformation(context), BlurTransformation(context, 10))
        ...
```

```kotlin:v4
GlideApp.with(context)
        .load(urlString)
        .transform(MultiTransformation(GrayscaleTransformation(), BlurTransformation(10)))
        ...
```
コードを見てお気づきだと思いますが、v4では複数のTransformationを指定する際には`MultiTransformation`クラスのインスタンスを`.transform()`に渡してあげる必要があります。
ちょっと不便になったなあと感じる方もいるかもしれませんが、その代わりに(と言ってはなんですが)、`Transformation`インタフェースの`transform`メソッドの引数に`Context`が加わったことにより、カスタムTransformationのコンストラクタで`Context`を渡さなくてもよくなりました！
結局記述量はそれほど変わらないですね 笑

#### 追記
[Glide 4.1.0](https://github.com/bumptech/glide/releases/tag/v4.1.0)で、Multiple Transformationsのshortcutが追加されました。
具体的には以下のように記述します。

```kotlin:v4.2
GlideApp.with(context)
        .load(urlString)
        .transforms(GrayscaleTransformation(), BlurTransformation(10))
        ...
```
v3の時のように記述できるようになりました！！

### Custom Transformation
先ほども少し触れましたが、独自のTransformationを作成するには`Transformation`インタフェースを実装したクラスを作成する必要があります。
この`Transformation`インタフェースですが、v3とv4で大きく分けて2つの変更が加わりました。

1. `transform`メソッドの引数に`Context`が加わった
2. `getId()`メソッドの代わりに`updateDiskCacheKey(MessageDigest messageDigest)`を実装しなければならなくなった

これらの変更により、先ほどから紹介している[Glide Transformations][gt]をGlide v4で使用するには、使用したいカスタムTransformationを自分でv4での`Transformation`に適応させる必要があります。
ここでは詳しい解説はしませんが、[サンプルアプリ][MGS]内ではv4用に適応させたTransformationがいくつかあるので参考にしてみてください。
[Glide Transformations][gt]の方もおそらくGlide v4の正式リリースに合わせてv4向けに修正されるのではないでしょうか。

[gt]: https://github.com/wasabeef/glide-transformations
[MGS]: https://github.com/ronnnnn/GlideMigrationSample

## Transition
Glideを使用することで、表示する画像とplaceholderをクロスフェードさせたり、画像の表示アニメーションを設定することが可能になります。
v3とv4ではTransition周りに多くの変更が加わりました。これまでv3に慣れ親しんだ方はv4を使ってみて結構困惑するかもしれません。

### Cross Fade
まず一つ目の大きな変更は、v3ではplaceholderと表示する画像のクロスフェードがデフォルトでONになっていましたが、**v4ではデフォルトのクロスフェードはOFF**になりました。
v4でクロスフェードをONにするには、次のように記述します。

```kotlin:v4
GlideApp.with(context)
        .load(imageString)
        .placeholder(R.drawable.image_placeholder)
        .transition(DrawableTransitionOptions.withCrossFade())
        ...
```

`.transition()`の引数に`DrawableTransitionOptions#withCrossFade()`を設定する必要があります。`asBitmap()`を使用してBitmap形式に変換している場合は`BitmapTransitionOptions#withCrossFade()`を使用すれば良いです。

クロスフェードのアニメーションにかかる時間を変更したい場合は

```kotlin:v4
GlideApp.with(context)
        .load(imageString)
        .placeholder(R.drawable.image_placeholder)
        .transition(DrawableTransitionOptions.withCrossFade(1000)) // default is 300
        ...
```
という風に`withCrossFade()`の引数にミリ秒で時間を指定します。

![](https://github.com/ronnnnn/GlideMigrationSample/blob/master/images/cross_fade.gif?raw=true)

#### 追記
[Glide 4.1.0](https://github.com/bumptech/glide/releases/tag/v4.1.0)でdefaultのTransitionsを設定できるようになりました。
設定は`AppGlideModule`を継承しているクラスで行います。
defaultでCross Fadeをオンにしたい場合には

```kotlin:v4.2
override fun applyOptions(context: Context, builder: GlideBuilder) {
    builder.setDefaultTransitionOptions(Drawable::class.java, DrawableTransitionOptions.withCrossFade())
            .setDefaultTransitionOptions(Bitmap::class.java, BitmapTransitionOptions.withCrossFade())
    }
```
というように記述します。

また、defaultのCross Fadeはオンにしたいけど、一部ではオフにしたいという場合には、

```kotlin:v4.2
GlideApp.with(context)
        .load(imageString)
        .placeholder(R.drawable.image_placeholder)
        .transition(GenericTransitionOptions.withNoTransition())
        ...
```
として、`GenericTransitionOptions#withNoTransition`を使用すれば良いです。


### Animation
Glideではクロスフェード以外にもスライドインやズームインなど、様々なアニメーションを画像の表示時に指定することが可能です。
Glide v3では`.animate()`の引数にアニメーションを指定することで実現可能でした。
しかし、v4においてはクロスフェードの時と同様に`.transition()`を使用してアニメーションを指定するように変更されました。
例えば次のようなズームインアニメーションを指定したい場合には

```xml:R.anim.zoom_in
<?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>
```

```kotlin:v4
GlideApp.with(context)
        .load(imageString)
        .placeholder(R.drawable.image_placeholder)
        .transition(DrawableTransitionOptions().transition(R.anim.zoom_in))
        ...
```
という風に指定しなければいけません。
クロスフェードの時との違いは、**`DrawableTransitionOptions`クラスをインスタンス化し、その`transition`メソッドにアニメーションを指定**するという点です。
クロスフェードの時と同様、`asBitmap()`を指定している場合には`BitmapTransitionOptions`クラスに置き換えてください。

![](https://github.com/ronnnnn/GlideMigrationSample/blob/master/images/zoom_in.gif?raw=true)

また、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`][circleImageView]や[`ShapeImageView`][shapeImageView]といったImageViewの一部がクロップされているImageViewに対して、`.placeholder()`や`.thumbnail()`で指定した画像とクロスフェードさせようとした場合、読み込んだ画像がそのImageViewの形にクロップされずに表示されてしまいます。

![](https://github.com/ronnnnn/GlideMigrationSample/blob/master/images/shape_bad.gif?raw=true)

実装は次の通りです。

```kotlin:v4
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から残っている問題][existingIssue]で、v4でも発生します。
対処方法がいくつかあるので、紹介します。

1. クロスフェードさせない
    - そもそもクロスフェードが原因なので`.dontAnimate()`を使用して、クロスフェードをさせなければ問題はないです
2. `.circleCrop()`を使用
    - 円形のImageViewの場合はImageViewをクロップするのではなく、表示する画像を`.circleCrop()`を使用して円形にクロップしてあげれば、良いです。ただし、クロスフェードも効きませんし、`placeholder()`で指定した画像まではクロップされません。
3. animationを指定する
    - `.transition(DrawableTransitionOptions().transition(animate))`のanimateにフェードインのアニメーションを指定してあげることで、厳密には`.placeholder()`で表示した画像とのクロスフェードとまではいきませんが、それっぽく表示することが可能です。

どうしても一部のImageViewがクロップされているImageViewに対して、どうしてもクロスフェードをかけたいという場合には3の方法で妥協するしかないようです。

![](https://github.com/ronnnnn/GlideMigrationSample/blob/master/images/shape_good.gif?raw=true)

実装は次の通りです。

```kotlin:v4
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として表示した画像が残ってしまうという現象][transparentImage]が起きます。

![](https://github.com/ronnnnn/GlideMigrationSample/blob/master/images/transparent_bad.gif?raw=true)

この現象はv3では起こりませんが、v4では発生してしまいます。
この方法を解決するにはちょっと特殊な方法でCrossFadeをオンにする必要があります。

先ほども紹介しましたが、一般的な画像に対してクロスフェードをかけたい場合には

```kotlin:v4
GlideApp.with(context)
        .load(imageString)
        .placeholder(R.drawable.image_placeholder)
        .transition(DrawableTransitionOptions.withCrossFade())
        ...
```
でクロスフェードをオンにする必要がありました。
しかし、この特殊な場合には

```kotlin:v4
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))
        ...
```
というように、明示的にクロスフェードを使用できるよう設定する必要があります。

![](https://github.com/ronnnnn/GlideMigrationSample/blob/master/images/transparent_good.gif?raw=true)

また、厳密にはクロスフェードとは異なりますが、フェードインアニメーションを使用することで、似たような挙動を実現することも可能です。

[circleImageView]: https://chromium.googlesource.com/android_tools/+/master/sdk/extras/android/support/v4/src/java/android/support/v4/widget/CircleImageView.java
[shapeImageView]: https://github.com/siyamed/android-shape-imageview
[existingIssue]: https://github.com/bumptech/glide#compatibility
[transparentImage]: http://bumptech.github.io/glide/doc/transitions.html#common-errors


## おわりに
これまで見ていただいた通り、Glide v3とv4では変更点が多くあり、マイグレーションが必須となります。実際にマイグレーションをしてみて、つまづいた点を中心にまとめてみました。
この記事で紹介した変更点が全てではなく、他にもannotation processingを使用した[`GlideExtension`][glideExtension]など魅力的な変更もあります。
~~Glide 4.0.0の正式リリースももう間も無くかと思うので、~~(8月2日に[Glide 4.0.0](https://github.com/bumptech/glide/releases/tag/v4.0.0)が、9月2日に[Glide 4.1.0](https://github.com/bumptech/glide/releases/tag/v4.1.0)が、10月4日に[Glide 4.2.0](https://github.com/bumptech/glide/releases/tag/v4.2.0)がリリースされています。)
ぜひ皆さんもお試しください！

間違いやもっといい方法あるよなどありましたら、コメントいただけると幸いです🙇

[glideExtension]: http://bumptech.github.io/glide/doc/generatedapi.html#glideextension


## おまけ (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` に対応 
    - https://github.com/bumptech/glide/commit/d83de421024882311c0aa4d835c8fce6a0550f8a
- Target APIが26に
    - https://github.com/bumptech/glide/commit/cea1cce41649602e4d3d3490303ea132c75f0332
- デフォルトのtransitionを設定可能に 
    - https://github.com/bumptech/glide/commit/0b99260f2f99b4b3c0ea5f4d7b309bc5a36d8d1c
- ネットワークリクエスト時のタイムアウトを設定可能に
    - https://github.com/bumptech/glide/commit/3e5527ebc8110c017037592aedc788f1d66f783f
- `trimMemory()` や `clearMemory()` を明示的に呼ぶ必要がなくなった
    - https://github.com/bumptech/glide/commit/6b137c2b1d4b2ab187ea2aa56834dea039daa090
- 複数のTransfomationを使用するときに、 `MultiTransformation` を使用しなくてよくなった
    - https://github.com/bumptech/glide/pull/2138

#### API/Behavior changes
- cross fade transitionの実装がViewAnimationからTransitionDrawableに
- DecordeFormatを `DecodeFormat.ARGB_8888` か `DecodeFormat.RGB_565` に設定している場合、Hardware Bitmapを使用するように


### 4.2.0
https://github.com/bumptech/glide/releases/tag/v4.2.0

#### Features
- デフォルトの `Encorder` を変更可能に
    - https://github.com/bumptech/glide/pull/2349
- transcode時に `Option` を設定可能に
    - https://github.com/bumptech/glide/commit/134870e51e362f1648a607348ebb7cb9c51d0a8a

#### Behavior changes
- Viewサイズの計測方法が変更
    - https://github.com/bumptech/glide/issues/2431


### 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` が追加された
    - https://github.com/bumptech/glide/commit/56a427573bae591696d6986da4209757c36db9a3
- 最初の読み込みに失敗した際に、別の読み込みを開始できる `error()` が追加
    - https://github.com/bumptech/glide/commit/b06b0cc2bd79e10a77155466da8a83459edf371b
- bitmap drawableじゃないリソースのdecodeとtransformが可能に
    - https://github.com/bumptech/glide/issues/350
- thumbnailのthumbnailみたいなものを設定したい時にネストが深くならないよう、 `thumbnail()` に複数の `RequestBuilder` を設定可能に
    - https://github.com/bumptech/glide/commit/bc1b25ef058c03e70f9749e56a62d0371c9accb6
- request自体にも `Context` を渡すようになり、Glide自身もその `Context` のthemeを使用するように
    - https://github.com/bumptech/glide/commit/bbb25aff0e44e23fe437c24e55278fe1f12061cb
- `Bitmap` や `Drawable` 自体を `load` に渡すことが可能に
    - https://github.com/bumptech/glide/commit/7663c214e44964529173ca48e0faf3e588f5a386

#### Behavior Changes
- gif画像を扱う際の品質とメモリ使用が向上
    - https://github.com/bumptech/glide/commit/6f91031a7e7b3852a58f3271091913655aa0f7ea


### 4.4.0
https://github.com/bumptech/glide/releases/tag/v4.4.0

#### Features
- `Integer.MAX_VALUE` よりも大きなサイズのキャッシュが可能に
    - https://github.com/bumptech/glide/commit/d402780a638da1662b0190b918a578c391ddeb01
- Viewがdetachされた際にclearし、reattachされた際に処理を再開する `clearOnDetach()` が追加
    - https://github.com/bumptech/glide/commit/d0fd96780dccf00b5cffa43befa2d5566cacd1db
- Viewサイズを正しく計測するために、layoutされるまで待つ `waitForLayout()` が追加
    - https://github.com/bumptech/glide/commit/05b885422624170dd39c89ef55b802f3b63ffc44


### 4.5.0
https://github.com/bumptech/glide/releases/tag/v4.5.0

#### Features
- 全てのリクエストを一時停止するメソッドが利用可能に
    - https://github.com/bumptech/glide/commit/09e33a2133eb1d4005b227439c0c53c9c4e8c89b
- resource内の動画のデコードをサポート
    - https://github.com/bumptech/glide/commit/6e9866b5a19d06625006a9a8c605db21047df74b

#### Behavior Changes
- ライブラリの提供形式がデフォルトで `aar` になったため、 `@aar` 指定は不要に
    - https://github.com/bumptech/glide/commit/06ba3442fd8d25c943e986c2bd6c138aa4b390e3
- APIレベル 19未満を使用しているデバイスは `MemorySizeCaluculator.isLowMemoryDevice` で `true` が返されるように
    - https://github.com/bumptech/glide/commit/b221d4bbec138efcdb1aabd07600b7df713f9e40

#### Breaking Changes
- `@NonNull` `@Nullable` アノテーションが追加されたため、コンパイラプラグインによってはビルドに失敗するかも

#### Build Changes
- CompileSdkVersionとTargetSdkVersionが27に
    - https://github.com/bumptech/glide/commit/75c2a8b6d216013e7fbf797231839a8f4c82757a


### 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` アノテーションが追加
    - https://github.com/bumptech/glide/commit/35f6a0a43bf8ac645c8c5d0cb82f2936f172f7f9
    - https://github.com/bumptech/glide/commit/bfa237c19a7d742a4911e2744d174ae82f420ac0
    - https://github.com/bumptech/glide/commit/e9f682f9586a68f9322d978dda4856957167ff0b


### 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形式のデータに対応
    - https://github.com/bumptech/glide/commit/17c1c3d5781e953379904a60bae08524632e5053
- スクロール時のパフォーマンスが向上
    - https://github.com/bumptech/glide/commit/7664c826ef2a55c67a4b55fbe61e33203355f2ee
    - https://github.com/bumptech/glide/commit/d7635bda9105dbeb27ed8a3fbda69832396960f5
    - https://github.com/bumptech/glide/commit/7ff3bdeed52d6047e8e9f879ccb3f67afe50fa2d

#### Behavior Changes
- `RecyclerView` や `ListView` でpreloaderを使用している場合、最初のスクロール前に次のページをpreloadするように
    - https://github.com/bumptech/glide/commit/dd7fe186e0eb4ea2b17f8611317a2714b81ff03b

#### Breaking Changes
- `android.app.Fragment` の使用がdeprecatedに
    - https://github.com/bumptech/glide/commit/29d481ccdc8a0f0d7135359d970de071f73b6922
- depracatedだったtransformationのコンストラクタが削除された
    - https://github.com/bumptech/glide/commit/05e3215ceca003ee295ed373f86e17caa3568c10
    - https://github.com/bumptech/glide/commit/b68ba436aa8d022fdf906c010fabb0d690f3d18a
    - https://github.com/bumptech/glide/commit/2d0bc2de5c86d7f56ca77748733511669f80d32a


### 4.8.0
https://github.com/bumptech/glide/releases/tag/v4.8.0

#### Features
- 一つのリクエストに対して複数の `RequestListener` を設定可能に
    - https://github.com/bumptech/glide/commit/93289994a4ba59c6251aad0ccdf332c0d758d9c7

#### Deprecations
- `SimpleTarget` と `ViewTarget` がdeprecatedに

#### Behavior Changes
- `RequestManager` によって一時停止されたリクエストが即座に一時停止されるようになり、placeholderの表示が可能に
    - https://github.com/bumptech/glide/commit/a55e935eba859b9ea4f6e4357b8ac4e7e4a8327f

#### Breaking Changes
- `pause()` と `isPaused()` が `Request` インタフェースから削除された
    - https://github.com/bumptech/glide/commit/9089752d2a4f4ccd6e7a6a7bbf7ea85db3f0949b

#### Build Changes
- annotation processerがAndroidXをサポート
    - https://github.com/bumptech/glide/commit/c3328fe63214c0aedefca3d5496bb222a2fd29ef


### 4.9.0
https://github.com/bumptech/glide/releases/tag/v4.9.0

#### Features
- 自動生成されるAPIを使用せずとも `RequestOption` を `RequestBuilder` に設定可能に
    - https://github.com/bumptech/glide/commit/ed20643fb94d4e17f4cdb3699a6d83621408dd34
- Global/Activity/Fragmentのスコープに対応した `RequestListener` が追加
    - https://github.com/bumptech/glide/commit/37127f0f817d4a11dfdcc447946397b5288de593
- 不要なoverrideを可能な限りなくすために、 `CustomTarget` が追加
    - https://github.com/bumptech/glide/commit/b3b2d7aa84a5beb8eddea39f2ec0e8ba35ceaa20
- dynamic moduleを使用しているresourceの読み込みをサポート
    - https://github.com/bumptech/glide/pull/3308
- `transforms()` の代わりに `transform()` の引数に複数のtransformationを追加できるように
    - https://github.com/bumptech/glide/pull/3365
- `Animatable2Compat` が追加されたことにより、無限ループしないGIFアニメーションの終了が検知できるように
    - https://github.com/bumptech/glide/pull/3438

#### Deprecations
- `transforms()` がdepracatedに
    - https://github.com/bumptech/glide/commit/8a26a6b8d93cc629d423a316b1838b841e672099

#### Behavior Changes
- バックグラウンドでリクエストが開始された `RequestListener` のコールバックがバックグラウンドで呼ばれるように
    - https://github.com/bumptech/glide/commit/8f1ea5c07dff7ade8c49c324bcb5a7f40d0b4891

#### Build Changes
- incremental annotation processingに対応
    - https://github.com/bumptech/glide/pull/3508


### 4.10.0
https://github.com/bumptech/glide/releases/tag/v4.10.0

#### Features
- `GlideExecutor` をmockするライブラリが追加
    - https://github.com/bumptech/glide/commit/e021f6bf83c909a7511c8182cce0af9c58912834
- Guavaの `ListenableFuture` に対応したintegration libraryが追加
    - https://github.com/bumptech/glide/commit/9fb1036645ec4e7cb159e7ca215f85375d8e4f67
- 角丸の各角のradiusを変更できる `GranularRoundedCorners` が追加
    - https://github.com/bumptech/glide/commit/f36a9fa9182227d7cebb3b5eaa6cc26e7d26aea5
- resource isのcache keyがday/nightモードに対応
    - https://github.com/bumptech/glide/commit/1b391c42f22e967c070a6a105b1e37730ab6ea6e
- メモリのクリアを手動で行えるAPIが追加
    - https://github.com/bumptech/glide/commit/8a094e972e686ddd1223371c268f0a4758e0b1ef
- wide gamut color spacesに対応
    - https://github.com/bumptech/glide/commit/15a21b125d0d131df7bc405a947e69b4d40709ae
    - https://github.com/bumptech/glide/commit/7910f68b31c5f3fb465a2834b6b579464ef0f1c6

#### Build Changes
- TargetSdkVersionが28に
    - https://github.com/bumptech/glide/pull/3880
- AndroidXに対応
    - https://github.com/bumptech/glide/commit/d8278f43a94484f20822170b71ac7b66269a2aa6


### 4.11.0
https://github.com/bumptech/glide/releases/tag/v4.11.0

#### Features
- Glideの使用頻度が低いアプリケーションでメモリ使用を抑えるためにGlideのスレッドにtimeoutが設定できるように
    - https://github.com/bumptech/glide/commit/db3acefdd4206f669762bafb82a7db05118c336b
- キャッシュ分析のためにBitmapPoolの情報が取得可能に
    - https://github.com/bumptech/glide/commit/1382e566c5ce36cd915afbe9177315f5f9961e47
- デフォルト設定以外のDiskCacheStrategyを使っている場合でも、リモートの動画データからデコードが可能に
    - https://github.com/bumptech/glide/commit/919069837db6f8ad80b79901eb382a247020540d

#### Bugs
- ExifInterfaceの警告ログが発生してしまう問題を修正
    - https://github.com/bumptech/glide/issues/3851
    - https://github.com/bumptech/glide/commit/bd6f894adb2e77120b50199ae471a2e86443723f

## 参考
- [Glide v4 Documentation](http://bumptech.github.io/glide/)
- [Glide GitHub Repository](https://github.com/bumptech/glide)
- [Glide Transformations](https://github.com/wasabeef/glide-transformations)
- [画像読み込みライブラリ Glide の v4 を試してみる](http://qiita.com/ryugoo/items/df3ff453897379cc1bd0)
- [Future Studio](https://futurestud.io/tutorials/glide-getting-started)