画面遷移時にTransactionTooLargeExceptionが起きる

2018/02/14

画面遷移時にTransactionTooLargeExceptionが起きてアプリがクラッシュする不具合に見舞われました。

先に原因を書いておくと

  • Android7.0以上
  • EditTextに巨大なテキストが入っている

を満たしたときに起きる問題でした。

この問題の背景にはViewの状態保存とBundleの容量制限があります。

AndroidではActivity再生成時に各Viewの情報が自動的に保存/復元されます。 Android Developers

デフォルトでは、システムは Bundle のインスタンス状態を使用して、アクティビティのレイアウトの各 View オブジェクトに関する情報を保存しています(EditText オブジェクトに入力されたテキスト値など)。

とある通り。厳密にはViewにidが付与されていれば、という条件付きですが。

で、これが何を引き起こすのかと言うと「EditTextに巨大なテキストが入っていると画面遷移時にTransactionTooLargeExceptionが起きる」です。 IntentやBundleはParcelableです。Parcelableには容量制限があります。なので、

  1. EditTextの中身をBundleに詰めて保存しようとする
  2. 容量制限を超える
  3. TransactionTooLargeException発生!!

という流れでExceptionになってしまうのですね。

ちなみに3についてはOSのバージョンによって挙動が異なります。

  • Marshmallow(Android6.x)まで:Logcatに!!! FAILED BINDER TRANSACTION !!!というエラーが出力される。あふれたデータは捨てられる(はず)
  • Nougat(Android 7.0)以降:TransactionTooLargeExceptionが起きてアプリがクラッシュする

今まではこっそりとNGになっていたのが、Nougatからは明示的にNGになったわけです。

原因が分かれば対処は簡単。今回はActivityがpauseするタイミングでEditTextの中身をいったんメモリに逃がし、resumeで復元する、というやり方で対処しました。

TransactionTooLargeExceptionはIntentにうっかり巨大データ(Bitmapとか)を入れてしまうのがあるあるなので、そっちを疑っていて問題の切り分けに苦戦してしまいました...

参考情報




関連(するかもしれない)記事


おススメ