Android

OkHttp: Call.cancel が MainThread で実行されてクラッシュする

会社で開発している Android アプリで、通信に Square の OkHttp ライブラリを使っているのだけれど、HTTPS 通信時 Call.cancel() が MainThread を触ってクラッシュすることがあった。Android 3(API Level 11)以降、同期的な通信は OS によって許されていないためだ。

android.os.NetworkOnMainThreadException
       at android.os.StrictMode$AndroidBlockGuardPolicy.onNetwork(StrictMode.java:1126)
       at org.apache.harmony.xnet.provider.jsse.OpenSSLSocketImpl.close(OpenSSLSocketImpl.java:908)
       at com.squareup.okhttp.Connection.closeIfOwnedBy()
       at com.squareup.okhttp.OkHttpClient$1.newTransport()
       at com.squareup.okhttp.internal.http.HttpConnection.setTimeouts()
       at com.squareup.okhttp.internal.http.HttpTransport.createRequestBody()
       at com.squareup.okhttp.internal.http.HttpEngine.disconnect()
       at com.squareup.okhttp.Call.cancel()

以下のようなコードを書いて対処した:

public void cancel(final String tag) {
    Executor executor = mOkHttpClient.getDispatcher().getExecutorService();
    if (Looper.myLooper() != Looper.getMainLooper()) {
        mOkHttpClient.cancel(tag);
    } else {
        executor.execute(new Runnable() {
            @Override
            public void run() {
                mOkHttpClient.cancel(tag);
            }
        });
    }
}

MainThread にいる場合は、非同期的に Call.cancel() を呼んでいる。上記の例では、OkHttpClient.cancel() と書いているが、最終的に Call.cancel() を呼び出している。

これがクラッシュレポートの大半を占めていたのだが、アップデート後はピタリと止んだので、期待通りに動いていると思う。

この OkHttp のバグは、3.0 に修正されるようだ。→ Call.cancel shouldn't offend strict mode · Issue #1592 · square/okhttp