画面遷移時にTransactionTooLargeExceptionが起きる
画面遷移時にTransactionTooLargeExceptionが起きてアプリがクラッシュする不具合に見舞われました。
先に原因を書いておくと
- Android7.0以上
- EditTextに巨大なテキストが入っている
を満たしたときに起きる問題でした。
この問題の背景にはViewの状態保存とBundleの容量制限があります。
AndroidではActivity再生成時に各Viewの情報が自動的に保存/復元されます。 Android Developersに
デフォルトでは、システムは Bundle のインスタンス状態を使用して、アクティビティのレイアウトの各 View オブジェクトに関する情報を保存しています(EditText オブジェクトに入力されたテキスト値など)。
とある通り。厳密にはViewにidが付与されていれば、という条件付きですが。
で、これが何を引き起こすのかと言うと「EditTextに巨大なテキストが入っていると画面遷移時にTransactionTooLargeExceptionが起きる」です。 IntentやBundleはParcelableです。Parcelableには容量制限があります。なので、
- EditTextの中身をBundleに詰めて保存しようとする
- 容量制限を超える
- 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とか)を入れてしまうのがあるあるなので、そっちを疑っていて問題の切り分けに苦戦してしまいました...
参考情報
関連(するかもしれない)記事
おススメ