ListViewで写真一覧を作っており、写真はOkHttpというライブラリを用いてネットから取得するようにしています。
例えば、全50枚あるリストを勢い良くスクロールしている途中(序盤や中盤など)でタイトルに書いた例外が発生することがあります。
(ListViewが表示されてすぐスクロール開始したなら発生しない?)
キャンセル処理を行った時とその例外発生した時のImageViewのhashCode・読み込みURLを比較してみたところ、キャンセル処理を行ったかどうかにかかわらず発生するようです。
その例外は何が要因で発生するものなのでしょうか?
ちなみにOSはAndroid 4.4.2を使用しています。
その時の例外は以下の通りです。
javax.net.ssl.SSLException: SSL handshake aborted: ssl=0x648aa828: I/O error during system call, Bad file number
at com.android.org.conscrypt.NativeCrypto.SSL_do_handshake(Native Method)
at com.android.org.conscrypt.OpenSSLSocketImpl.startHandshake(OpenSSLSocketImpl.java:405)
at okhttp3.internal.io.RealConnection.connectTls(RealConnection.java:195)
at okhttp3.internal.io.RealConnection.connectSocket(RealConnection.java:148)
at okhttp3.internal.io.RealConnection.connect(RealConnection.java:111)
at okhttp3.internal.http.StreamAllocation.findConnection(StreamAllocation.java:188)
at okhttp3.internal.http.StreamAllocation.findHealthyConnection(StreamAllocation.java:127)
at okhttp3.internal.http.StreamAllocation.newStream(StreamAllocation.java:97)
at okhttp3.internal.http.HttpEngine.connect(HttpEngine.java:289)
at okhttp3.internal.http.HttpEngine.sendRequest(HttpEngine.java:241)
at okhttp3.RealCall.getResponse(RealCall.java:240)
at okhttp3.RealCall$ApplicationInterceptorChain.proceed(RealCall.java:198)
at okhttp3.RealCall.getResponseWithInterceptorChain(RealCall.java:160)
at okhttp3.RealCall.access$100(RealCall.java:30)
at okhttp3.RealCall$AsyncCall.execute(RealCall.java:127)
at okhttp3.internal.NamedRunnable.run(NamedRunnable.java:32)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1112)
読み込みコードは以下の通りです。
/**
* URLから写真をロードしてセット.
* 写真はViewに対して任意に設定したサイズでロードされる。
*
* @param photoUrl 写真取得に使用するURL
*/
protected void loadPhoto(final String photoUrl) {
if (getTag() != null) {
((Call) getTag()).cancel();
}
setImageResource(R.drawable.loading_animation);
((AnimationDrawable) getDrawable()).start();
Request request = new Request.Builder()
.url(photoUrl)
.get()
.build();
OkHttpClient client = new OkHttpClient();
Call call = client.newCall(request);
setTag(call);
call.enqueue(new Callback() {
/**
* リクエストキャンセル・接続の問題・タイムアウトのために実行できなった場合
*
* @param call
* @param e エラー内容
*/
@Override
public void onFailure(Call call, IOException e) {
setTag(null); //通信終了
e.printStackTrace();
if (e instanceof SocketException) {
//キャンセル要求による反応は何もしない
return;
}
//それ以外は接続切れ扱い
Handler handler = new Handler(Looper.getMainLooper());
handler.post(new Runnable() {
@Override
public void run() {
setImageResource(R.drawable.error);
}
});
EventBus.getDefault().post(UserEvent.connectionError(""));
}
/**
* 応答が正常に返された場合
* エラーステータスも含む
*
* @param call
* @param response リクエストの結果
*/
@Override
public void onResponse(Call call, Response response) {
setTag(null);
if (!response.isSuccessful()) {
EventBus.getDefault().post(UserEvent.connectionError(String.valueOf(response.code())));
return;
}
InputStream inputStream = response.body().byteStream();
final Bitmap bitmap = BitmapFactory.decodeStream(inputStream);
Handler handler = new Handler(Looper.getMainLooper());
handler.post(new Runnable() {
@Override
public void run() {
setImageBitmap(bitmap);
}
});
response.body().close();
}
});
}