Как передать данные при открытии Fragment?
Передача данных при открытии Fragment — это одна из самых распространённых задач в Android, и она имеет несколько корректных и безопасных способов реализации. Важно помнить, что фрагмент создаётся не напрямую через конструктор, а через фабричный метод с использованием Bundle.
✅ Стандартный способ — через arguments: Bundle
1. Создание экземпляра через newInstance()
class DetailsFragment : Fragment() {
companion object {
private const val ARG_USER_ID = "user_id"
fun newInstance(userId: String): DetailsFragment {
val fragment = DetailsFragment()
val bundle = Bundle()
bundle.putString(ARG_USER_ID, userId)
fragment.arguments = bundle
return fragment
}
}
}
2. Получение данных внутри фрагмента
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val userId = arguments?.getString(ARG_USER_ID)
}
🔹 Такой способ безопасен при восстановлении состояния после пересоздания фрагмента (например, после поворота экрана).
📦 Что можно положить в Bundle
-
Примитивы (Int, String, Boolean, и т.д.)
-
Parcelable (предпочтительно)
-
Serializable (медленнее, но проще)
-
Списки этих типов
-
Bundle внутри другого Bundle
🔄 Альтернативы и современные подходы
1. Safe Args (для Navigation Component)
Если вы используете Jetpack Navigation, лучше всего передавать аргументы через Safe Args — плагин, который создаёт типобезопасные классы аргументов.
В navigation.xml:
<fragment
android:id="@+id/detailsFragment"
android:name="com.example.DetailsFragment">
<argument
android:name="userId"
app:argType="string" />
</fragment>
Передача:
val action = MainFragmentDirections.actionToDetailsFragment(userId = "123")
findNavController().navigate(action)
Получение:
val userId = arguments?.let { DetailsFragmentArgs.fromBundle(it).userId }
🔹 Типобезопасно, меньше ошибок, IDE подсказывает имена и типы.
2. ViewModel (shared ViewModel между Fragment)
Для обмена между фрагментами в одном Activity можно использовать общую ViewModel:
val sharedViewModel: SharedViewModel by activityViewModels()
sharedViewModel.selectedUserId.value = "123"
И в другом фрагменте:
sharedViewModel.selectedUserId.observe(viewLifecycleOwner) {
// использовать значение
}
🔹 Удобно при сложных сценариях: мастер-деталь, вкладки, многократная навигация.
3. Navigation BackStackEntry.savedStateHandle
Можно передать данные назад при возврате к предыдущему фрагменту:
findNavController().previousBackStackEntry
?.savedStateHandle
?.set("key", value)
И считать позже:
val value = savedStateHandle.get<String>("key")
⚠️ Что делать не рекомендуется
❌ Создавать фрагмент с конструктором с параметрами — фрагмент может быть пересоздан системой без них.
class MyFragment(private val userId: String) : Fragment() // Плохо
❌ Передавать сложные объекты через глобальные singletons, если они не нужны более чем на один экран.
📌 Вывод
Для передачи данных при открытии фрагмента:
-
Используйте Bundle через arguments — это базовый, безопасный и универсальный способ.
-
Для типобезопасности и сложной навигации применяйте Safe Args.
-
При работе с множеством фрагментов — удобно использовать shared ViewModel.
-
Не создавайте фрагменты с параметрами в конструкторе — это нарушает контракт Android и приведёт к краху при пересоздании.