Google製 通信ライブラリ Cronet

## Cronetとは

Google製の通信ライブラリ
https://developer.android.com/guide/topics/connectivity/cronet?hl=ja
Sample
https://github.com/GoogleChromeLabs/cronet-sample

AndroidDeveloperによると、YoutubeなどGoogleアプリで使われているとのことでした。

Retrofit + Okhttp一強の時代（だと思っている）ですが
他のネットワーク系のライブラリに触れる機会がなかったので勉強がてらに触ってみました。

## 使い方
ともあれ早速使ってみましょう！

サンプルのリポジトリには、ソースをcloneして使ってくれとあるのですが、mavenリポジトリに登録がありました。
https://mvnrepository.com/artifact/com.google.android.gms/play-services-cronet

```gradle
dependencies {
    api "com.google.android.gms:play-services-cronet:18.0.0"
}
```

今回APIは、Qiita API v2を利用しました。
Sampleにあったものは画像をそのままロードするようなものだったのですが、これは文字列を最終的に取り出してみました。

UrlRequest.Callbackを継承したCronetCallbackクラスでネットワークの通信状態を受け取ります。
onSucceededメソッドで最終的にJSONの文字列を受け取ります。

```java
public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        // Cronet準備
        CronetEngine.Builder engineBuilder = new CronetEngine.Builder(getApplicationContext());
        //  HTTP/2とQiucでの通信を許可
        engineBuilder.enableHttp2(true).enableQuic(true);
        CronetEngine engine = engineBuilder.build();

　　　　　// 通信をするExecutorを指定できる
        // これは一つのスレッドですが、複数のスレッドを指定することができそうです
        Executor executor = Executors.newSingleThreadExecutor();
        CronetCallback callback = new CronetCallback();
        UrlRequest.Builder requestBuilder = engine.newUrlRequestBuilder(
                "https://qiita.com/api/v2/items", callback, executor);
        UrlRequest request = requestBuilder.build();

        // リクエスト開始
        request.start();
    }

    /**
     * onResponseStarted
     * onReadCompleted
     * onSucceeded の順で呼ばれる
     * 次のメソッドを通知したい場合、オーバーライドしたメソッドでrequest.read(byteBuffer)を呼ぶ
     */
    private class CronetCallback extends UrlRequest.Callback {

        private ByteArrayOutputStream bytesReceived = new ByteArrayOutputStream();
        private WritableByteChannel receiveChannel = Channels.newChannel(bytesReceived);

        @Override
        public void onRedirectReceived(UrlRequest request, UrlResponseInfo info, String newLocationUrl) {
            Log.d("CronetCallback", "onRedirectReceived");
            // リダレクトを許可する場合
            request.followRedirect();

            // リダイレクトを許可しない場合
            // request.cancel();
        }

        @Override
        public void onResponseStarted(UrlRequest request, UrlResponseInfo info) {
            Log.d("CronetCallback", "onResponseStarted");
            int statusCode = info.getHttpStatusCode();
            // ステータスコードが200系だったので中身をリードする
            if (statusCode <= 200 && statusCode < 300) {
                request.read(ByteBuffer.allocateDirect(32 * 1024));
            } else {
                // ステータスコードが200系以外
            }
        }

        @Override
        public void onReadCompleted(UrlRequest request, UrlResponseInfo info, ByteBuffer byteBuffer) {
            // リクエスト完了
            Log.d("CronetCallback", "onReadCompleted");
            byteBuffer.flip();
            try {
                receiveChannel.write(byteBuffer);
            } catch (IOException e) {
            }
            byteBuffer.clear();
            request.read(byteBuffer);
        }

        @Override
        public void onSucceeded(UrlRequest request, UrlResponseInfo info) {
            // リクエスト成功
            Log.d("CronetCallback", "onSucceeded");
            byte[] byteArray = bytesReceived.toByteArray();
            String json = new String(byteArray);
            Log.d("CronetCallback", "json " + json);
        }

        @Override
        public void onFailed(UrlRequest request, UrlResponseInfo info, CronetException error) {
            Log.d("CronetCallback", "onFailed : " + error.getMessage());
        }
    }
}
```

### 余談
Exoplayerにも通信部分をCronetで行うextensionsが追加されています。
実際にこのextensionsを使ってみたところ、Explayerのサンプル動画が再生できました。(okhttp版もあります)
https://github.com/google/ExoPlayer/tree/release-v2/extensions/cronet


### 所感
リダイレクトの指定があったら、レスポンスを受け取った時にステータスコードをみて次の処理に飛ばすか
などあり、その点便利かなと思いました。
そしてやっぱretrofitすごい