Volleyはどのようにネットワーク通信を非同期で行っているのか

すごい今更感ある内容ですが、 [AsyncTaskの非同期処理はどのように実現しているのか
](http://qiita.com/kazy/items/755e8d3e9e36f5730895)の続きみたいな記事です。

#### はじめに

[Volley](https://android.googlesource.com/platform/frameworks/volley/)は2013年のGoogle I/Oで発表され爆発的な人気を博しながらも、現在では少しだけ衰退気味のHttpクライアントですね。私の場合は、仕事のコードがvolleyラッパーのAPIクライアントを使っていて、趣味では[OkHttp](http://square.github.io/okhttp/)をメインに使っています。Volleyが特徴的なのはHttpクライアントでありながら自身で非同期処理の仕組みを提供していることころです。本稿ではVolleyがどのように非同期処理を実現しているのかについて紹介します。細かい説明はかなり省いて、どちらかと言うとおおまかな設計を掴んで頂けるように努力します。

#### Volleyのコードのcloneする

よくわかってないのですが、[このレポジトリ(Volley)](https://android.googlesource.com/platform/frameworks/volley/)からgit cloneするのが正しそうです。
そのまま既存のプロジェクトに取り込んでもいいですし、状況に応じてjarにしてプロジェクトにとり込みましょう。(なんで maven repoに上げないんですかね..)

#### 非同期処理の主な登場人物

非同期処理の中核部分にいるのは、[`NetworkDispatcher`](https://android.googlesource.com/platform/frameworks/volley/+/jb-mr2.0-release/src/com/android/volley/NetworkDispatcher.java)と[`PriorityBlockingQueue`](https://docs.oracle.com/javase/jp/6/api/java/util/concurrent/PriorityBlockingQueue.html)です。PriorityBlockingQueueは`java.util.concurrent`で提供されているクラスで名前の通り優先度付きのBlocking付きのqueueですね。何がBlokingかというとqueueから値を受け取り時に新しいitemが入ってくるまで処理をブロックして待ち続けます。 NetworkDispatcherとはThreadを継承しているクラスなので、こいつが実質非同期処理を行うworkerスレッドの正体ということになります。
つまりPriorityBlockingQueueにRequestインタンスが続々と格納され、それをNetworkDispatcherが受け取ってネットワーク処理をバックグランドで行うということですね。思ってるほど難しくなく結構シンプルな構成ですね。`NetworkDispatcher#run`(非同期処理の実行部分)は簡略するとこんな感じです。

```java
@Override
public void run() {
    Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
    while (true) {
        Request<?> request;
        try {
            request = mQueue.take(); // PriorityBlockingQueue(mQueue)から次のリクエストが受け取れるまでひたすら待つ
        } catch (InterruptedException e) {
            continue;
        }

        try {
            Response<?> response = request.parseNetworkResponse(networkResponse);
            mDelivery.postResponse(request, response); // ExecutorDelivery(mDelivery)経由でHandlerを呼び出して、UIスレッドに結果を返す。
        } catch (Exception e) {
            mDelivery.postError(request, volleyError); // 実行中に何か例外が発生した場合はその結果をUIスレッドに返す。
        }
    }
}
```

#### Volleyにおける並列処理の仕組み

`NetworkDispatcher`は実質単一のスレッドなのでこれだけでは、httpリクエストの並行で捌くことは出来ません。なので一般的には内部にスレッドプールを用意していい感じに各スレッドに仕事を割り振る仕組みが必要です。Volleyでこのような役割をになっているのは[`RequestQueue`](https://android.googlesource.com/platform/frameworks/volley/+/idea133/src/com/android/volley/RequestQueue.java)クラスです。RequestQueueは`NetworkDispatcher[ ] mDispatchers`をメンバ変数に持ち、初期化のタイミングでNetworkDispatcherを生成します。つまり`RequestQueue`と`NetworkDispatcher`の組み合わせによってスレッドプールみたいな役割をします。またthreadのstartやstopも全てRequestQueue内で行われます。mDispatchersのサイズはRequestQueueのコンストラクタで指定され、デフォルト値が **4** になっています。適切なスレッド数というは難しく、端末の性能やネットワークの品質にもたぶん影響します。画像のダウンロードに関する適切なスレッド数の考察は[モバイルアプリのスレッドプールサイズの最適化（画像読み込み編）](http://techlife.cookpad.com/entry/2015/12/21/110416)の記事で詳しい説明があります。

### おわり
内部実装読むのは楽しいですね。 Volleyは[Marshmallowで消されてしまった](https://developer.android.com/intl/ja/about/versions/marshmallow/android-6.0-changes.html#behavior-apache-http-client)`org.apache.http`パッケージに依存していることから最近ではオワコン感ありますが、実際ほとんどの依存は[`HurlStack`](https://android.googlesource.com/platform/frameworks/volley/+/c3dea925af9b3523e2e01e8b7799e71ef558c1c5/src/com/android/volley/toolbox/HurlStack.java)のみでHttpStack自体は外から入れ替え可能なのでHttpStackをOkhttpベースにするなどすれば別に使いつづけても問題ないような印象を受けました。まあでも、2016年なら普通に[OkHttp](http://square.github.io/okhttp/)をつかうといいとおもいます。非同期処理の機能(workerスレッドの管理/扱い)はOkHttpにはないので、AsyncTaskなりRxJavaなり使ったらいいんじゃないのでしょうか。ちなみにRxJavaはとても良いですよ。
ところで、実装を追っていてスレッドプール相当の部分の実装は`java.util.concurrent`の[ThreadPoolExecutor](http://developer.android.com/intl/ja/reference/java/util/concurrent/ThreadPoolExecutor.html)とか使って楽できそうな印象があったのですが、なぜ生のスレッドを管理しているんだろうという疑問がありました。実装はかなりななめ読みなので見落としてることや勘違いしてることがあるんでしょうか またわかったら追記しますね。