概要
Picasso (ver:2.5.2)を利用していて下記の現象に遭遇したので対処方法をメモします。
現象
発生した環境
ニュース系アプリのUIによくある複数タブにRecyclerView(大量のImageViewを含む)があり、スワイプで行き来ができるアプリを作っていたときに確認しました。
起こった現象
タブをスワイプで遷移している際、スワイプを繰り返していると画面がフリーズして操作できなくなります。
(エラーログ)
2019-03-28 15:33:55.067 xxxx E/NativeCrypto: AppData::create pipe(2) failed: Too many open files
2019-03-28 15:33:55.351 xxxx E/NativeCrypto: AppData::create pipe(2) failed: Too many open files
2019-03-28 15:33:55.380 xxxx E/NativeCrypto: AppData::create pipe(2) failed: Too many open files
2019-03-28 15:33:55.393 xxxx E/NativeCrypto: AppData::create pipe(2) failed: Too many open files
2019-03-28 15:33:55.642 xxxx E/NativeCrypto: AppData::create pipe(2) failed: Too many open files
2019-03-28 15:33:55.672 xxxx E/NativeCrypto: AppData::create pipe(2) failed: Too many open files
....
原因
PicassoでImageViewにfit()メソッドを利用して画像を読みこませている際、発生する可能性があります。
今回は大量のimageViewへの読み込みを行なっていたので発生しやすくなっていました。(端末のスペックによります。)
原因箇所としては、最新版で追加されている下記の条件分岐が、2.5.2以前のバージョンには含まれていないことによります。
https://github.com/square/picasso/blob/master/picasso/src/main/java/com/squareup/picasso3/Picasso.java#L536
Picassoでは、fit()を使わない場合と使う場合で描画までの処理が異なります。
fit()を利用する場合、Picasso内で「deferred」変数がtrueになり、deferredがtrueのリクエストが蓄積されるMapにputされていき、後で順番に処理をされます。
一方、fit()を利用しない場合deferred扱いにならずにそのまま処理されます。
下記の条件分岐がver.2.71828で追加されていますが、ver.2.5.2にはこの処理が含まれていません。
https://github.com/square/picasso/blob/master/picasso/src/main/java/com/squareup/picasso3/Picasso.java#L536
この条件分岐が含まれていない場合、処理待ちのMapに同じImageViewについてのリクエストが重複してputされていってしまう可能性があり、その重複したリクエストを処理しようとすることで今回のようなエラーが発生します。
解決策
おとなしくバージョンアップしましょう。
https://github.com/square/picasso
2.5.2 -> 2.71828
数年分のcommitが含まれる(上述した条件分岐は4年前のcommit)ので変更点が多いことや、バージョン名への不安感などからバージョンアップをためらいたくなりますが、上記問題はバージョンアップによって解決します。
そもそもfitメソッドを利用する必要がなければ、利用しないという解決策もありますが、deferred扱いにしないことによって、パフォーマンスが落ちるケースがあり得ます。