[Android]Glideのネットワークエラー後の画像再リクエスト機能について

Android 開発で [Glide](https://github.com/bumptech/glide) はよく使われる画像ローダーライブラリの一つです。

この Glide にはネットワークエラーで画像の取得に失敗した場合でも、通信状況が復帰したタイミングで自動的に画像の再リクエストを行う機能があります。

この機能について深堀りしていきたいと思います。

※ 動作確認は Glide v4.12.0 で行っています。

# 画像再リクエストが行われるまでの流れ

Glide では [DefaultConnectivityMonitor](https://github.com/bumptech/glide/blob/v4.12.0/library/src/main/java/com/bumptech/glide/manager/DefaultConnectivityMonitor.java) というクラスでネットワーク状況の監視が行われています。

ネットワーク状況が回復したタイミングで、このクラスは登録されたリスナーに通知します。

- https://github.com/bumptech/glide/blob/v4.12.0/library/src/main/java/com/bumptech/glide/manager/DefaultConnectivityMonitor.java#L30-L44

```java
  private final BroadcastReceiver connectivityReceiver =
      new BroadcastReceiver() {
        @Override
        public void onReceive(@NonNull Context context, Intent intent) {
          boolean wasConnected = isConnected;
          isConnected = isConnected(context);
          if (wasConnected != isConnected) {
            if (Log.isLoggable(TAG, Log.DEBUG)) {
              Log.d(TAG, "connectivity changed, isConnected: " + isConnected);
            }

            listener.onConnectivityChanged(isConnected);
          }
        }
      };
```

この通知は [RequestManager.RequestManagerConnectivityListener#onConnectivityChanged](https://github.com/bumptech/glide/blob/v4.12.0/library/src/main/java/com/bumptech/glide/RequestManager.java#L717-L723) メソッドで受け取り、このメソッド内で画像の再リクエストが行われます。

```java
  private class RequestManagerConnectivityListener
      implements ConnectivityMonitor.ConnectivityListener {
    @GuardedBy("RequestManager.this")
    private final RequestTracker requestTracker;

    RequestManagerConnectivityListener(@NonNull RequestTracker requestTracker) {
      this.requestTracker = requestTracker;
    }

    @Override
    public void onConnectivityChanged(boolean isConnected) {
      if (isConnected) {
        synchronized (RequestManager.this) {
          requestTracker.restartRequests();
        }
      }
    }
  }
```

# 画像再リクエストが行われる条件

[RequestManager のコンストラクタ](https://github.com/bumptech/glide/blob/v4.12.0/library/src/main/java/com/bumptech/glide/RequestManager.java#L127-L130) にて [ConnectivityMonitorFactory](https://github.com/bumptech/glide/blob/master/library/src/main/java/com/bumptech/glide/manager/ConnectivityMonitorFactory.java) が [ConnectivityMonitor](https://github.com/bumptech/glide/blob/master/library/src/main/java/com/bumptech/glide/manager/ConnectivityMonitor.java) のインスタンスを生成します。

```java 
  RequestManager(
      Glide glide,
      Lifecycle lifecycle,
      RequestManagerTreeNode treeNode,
      RequestTracker requestTracker,
      ConnectivityMonitorFactory factory,
      Context context) {
    this.glide = glide;
    this.lifecycle = lifecycle;
    this.treeNode = treeNode;
    this.requestTracker = requestTracker;
    this.context = context;

    connectivityMonitor =
        factory.build(
            context.getApplicationContext(),
            new RequestManagerConnectivityListener(requestTracker));

    ...
  }
```

この `ConnectivityMonitorFactory` は特に何も設定しなければ [DefaultConnectivityMonitorFactory](https://github.com/bumptech/glide/blob/master/library/src/main/java/com/bumptech/glide/manager/DefaultConnectivityMonitorFactory.java) が使われます。

このクラスを見ると、`android.permission.ACCESS_NETWORK_STATE` パーミッションが許可されている場合に `DefaultConnectivityMonitor` を、そうでない場合は何もチェックを行わない [NullConnectivityMonitor](https://github.com/bumptech/glide/blob/master/library/src/main/java/com/bumptech/glide/manager/NullConnectivityMonitor.java) のインスタンスを生成するようになっています。

```java
  public ConnectivityMonitor build(
      @NonNull Context context, @NonNull ConnectivityMonitor.ConnectivityListener listener) {
    int permissionResult = ContextCompat.checkSelfPermission(context, NETWORK_PERMISSION);
    boolean hasPermission = permissionResult == PackageManager.PERMISSION_GRANTED;
    if (Log.isLoggable(TAG, Log.DEBUG)) {
      Log.d(
          TAG,
          hasPermission
              ? "ACCESS_NETWORK_STATE permission granted, registering connectivity monitor"
              : "ACCESS_NETWORK_STATE permission missing, cannot register connectivity monitor");
    }
    return hasPermission
        ? new DefaultConnectivityMonitor(context, listener)
        : new NullConnectivityMonitor();
  }
```

ですので `AndroidManifest.xml` に `android.permission.ACCESS_NETWORK_STATE` が設定されている場合などは、ネットワーク状況が回復したタイミングで画像の再リクエスト処理が行われることになります。

# 画像再リクエストを無効化する方法

この画像再リクエストの機能は、アプリによっては不要な場合もあり得るかと思います。

この機能を無効化するためには `ConnectivityMonitorFactory` を継承したクラスを作成し、何もしない `ConnectivityMonitor` を返すようにします。

そのためには　`AppGlideModule` を継承したクラスで以下のように設定することで可能になります。


```kotlin
@GlideModule
class GlideModule : AppGlideModule() {

    override fun applyOptions(context: Context, builder: GlideBuilder) {
        ...
        
        builder.setConnectivityMonitorFactory { _, _ -> NullConnectivityMonitor() }
    }
    
    private class NullConnectivityMonitor : ConnectivityMonitor {
        override fun onStart() {
        }

        override fun onStop() {
        }

        override fun onDestroy() {
        }
    }
}
```