Может ли фрагмент быть не прицеплен к Activity и почему
Что проверяют
Понимаете ли вы, что жизненные циклы фрагмента, его View и Activity не совпадают и между ними бывают разрывы. На практике вопрос о том, откуда берётся IllegalStateException с текстом «not attached to a context», а следом о том, как безопасно подписываться на данные.
Как отвечать
Да, может, и это нормальное состояние, а не ошибка. Типичные случаи:
- создан, но не добавлен: объект создан через
newInstance(), транзакция ещё не выполнена.getActivity()вернётnull,isAdded()вернётfalse; - удалён: после
remove()илиreplace()безaddToBackStack()фрагмент проходитonDestroy()иonDetach(), но объект жив, пока на него ссылается, например, незавершённый сетевой колбэк; - смена конфигурации: при повороте старая Activity уничтожается, старый экземпляр фрагмента отцепляется, а
FragmentManagerсоздаёт новый через конструктор без аргументов и восстанавливаетarguments. Всё, что передали в конструктор, теряется; detach(): фрагмент убирается из UI, егоViewуничтожается, но состояние остаётся вFragmentManager.
Разведите два жизненных цикла. В back stack у фрагмента вызывается onDestroyView(), но не onDetach(): фрагмент прикреплён, а View уже нет. Отсюда правило обнулять binding в onDestroyView() и подписываться через viewLifecycleOwner.
Как защищаться: собирать Flow в viewLifecycleOwner.lifecycleScope внутри repeatOnLifecycle(Lifecycle.State.STARTED), наблюдать LiveData с viewLifecycleOwner, а долгую работу вести во ViewModel, которая не держит ссылок на фрагмент. Тогда корутины отменятся сами, когда View уничтожится.
Где спотыкаются
Лечат падения проверкой isAdded() перед каждым requireContext(). Это заплатка: работа всё равно выполняется впустую, а утечка остаётся.
Передают данные через конструктор. После поворота или смерти процесса фрагмент пересоздаётся без них, данные нужно класть в arguments.
Путают отцепление фрагмента с уничтожением View и подписываются с this вместо viewLifecycleOwner. После возврата из back stack наблюдатель регистрируется второй раз, и обновления приходят дважды.