Как передать данные при открытии 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" />
&lt;/fragment&gt;

Передача:

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&lt;String&gt;("key")

⚠️ Что делать не рекомендуется

Создавать фрагмент с конструктором с параметрами — фрагмент может быть пересоздан системой без них.

class MyFragment(private val userId: String) : Fragment() // Плохо

Передавать сложные объекты через глобальные singletons, если они не нужны более чем на один экран.

📌 Вывод

Для передачи данных при открытии фрагмента:

  • Используйте Bundle через arguments — это базовый, безопасный и универсальный способ.

  • Для типобезопасности и сложной навигации применяйте Safe Args.

  • При работе с множеством фрагментов — удобно использовать shared ViewModel.

  • Не создавайте фрагменты с параметрами в конструкторе — это нарушает контракт Android и приведёт к краху при пересоздании.