Есть ли ограничения по объему данных в Bundle
Что проверяют
Знаете ли вы, откуда берётся ограничение и где оно реально бьёт, а не только цифру «1 МБ». Следом обычно спрашивают, как передать между экранами большой объект и что делать с TransactionTooLargeException в отчётах о крашах.
Как отвечать
Сам Bundle в памяти ничем не ограничен. Лимит появляется, когда он сериализуется в Parcel и уходит через Binder:
- буфер транзакций Binder: около 1 МБ на процесс, и он общий для всех транзакций, идущих в этот момент. Поэтому упасть можно на данных заметно меньше мегабайта;
- где это случается: extras в
IntentприstartActivity(), аргументы фрагмента,onSaveInstanceState()иSavedStateHandle. Сохранённое состояние уходит в системный процесс; - поведение: для приложений с
targetSdk24 и выше превышение при сохранении состояния даётTransactionTooLargeExceptionи краш. Раньше состояние терялось молча; - рекомендация документации: держать сохранённое состояние меньше 50 КБ.
Что передавать вместо больших объектов:
- идентификатор: в
Bundleкладутid, а данные следующий экран берёт из Room или репозитория; - общая
ViewModel: для фрагментов одной активити или одного графа навигации. Смерть процесса она не переживает, поэтому минимальное состояние всё равно сохраняют; - файлы и картинки:
UriчерезFileProvider, а неByteArrayилиBitmapв extras.
И выбирайте Parcelable через плагин kotlin-parcelize: Serializable работает медленнее и занимает больше места.
Где спотыкаются
Называют «лимит Bundle 1 МБ» и считают, что 900 КБ пройдут. Буфер делится со всеми параллельными транзакциями процесса.
Кладут в extras Bitmap или список из сотен моделей. На своём телефоне работает, в продакшене падает при сворачивании приложения, когда система сохраняет состояние.
Предлагают ViewModel как полную замену onSaveInstanceState(). После смерти процесса она пустая, и пользователь теряет введённые данные.