← Назад к вопросам

Какие знаешь способы передачи данных между двумя фрагментами?

1.8 Middle🔥 252 комментариев
#Android компоненты#Архитектура и паттерны

Комментарии (2)

🐱
deepseek-v3.2PrepBro AI6 апр. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Способы передачи данных между фрагментами в Android

В архитектуре Android приложений фрагменты являются модульными компонентами, которые должны быть максимально декомпонованы и переиспользуемы. Существует несколько подходов к передаче данных между фрагментами, каждый из которых подходит для разных сценариев. Выбор зависит от степени связанности фрагментов, объема данных и жизненного цикла компонентов.

1. Через общую Activity (ViewModel или интерфейсы)

Это наиболее рекомендуемый подход, особенно с появлением Android Architecture Components. Фрагменты не должны общаться напрямую, а через общий хостинг-компонент (Activity или Navigation).

Использование Shared ViewModel:

// ViewModel, общее для Activity и фрагментов
class SharedViewModel : ViewModel() {
    private val _data = MutableLiveData<String>()
    val data: LiveData<String> = _data
    
    fun updateData(newValue: String) {
        _data.value = newValue
    }
}

// Фрагмент-отправитель
class FragmentA : Fragment() {
    private val viewModel: SharedViewModel by activityViewModels()
    
    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        button.setOnClickListener {
            viewModel.updateData("Данные из FragmentA")
        }
    }
}

// Фрагмент-получатель
class FragmentB : Fragment() {
    private val viewModel: SharedViewModel by activityViewModels()
    
    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        viewModel.data.observe(viewLifecycleOwner) { data ->
            textView.text = data // Реактивное обновление UI
        }
    }
}

Преимущества:

  • Соответствует принципам MVVM и Single Source of Truth
  • Данные сохраняются при смене конфигурации
  • Автоматическая очистка при уничтожении Activity

2. С использованием интерфейсов обратного вызова

Классический подход, где Activity выступает посредником:

// Интерфейс для коммуникации
interface DataTransferListener {
    fun onDataTransferred(data: String)
}

// Activity реализует интерфейс
class HostActivity : AppCompatActivity(), DataTransferListener {
    override fun onDataTransferred(data: String) {
        val fragmentB = supportFragmentManager.findFragmentById(R.id.fragment_b) as FragmentB
        fragmentB.receiveData(data)
    }
}

// Фрагмент-отправитель
class FragmentA : Fragment() {
    private var listener: DataTransferListener? = null
    
    override fun onAttach(context: Context) {
        super.onAttach(context)
        listener = context as? DataTransferListener
    }
    
    private fun sendData() {
        listener?.onDataTransferred("Данные из FragmentA")
    }
}

3. Через аргументы (Bundle)

Используется для передачи данных при создании фрагмента или между фрагментами через Navigation Component:

// Отправка данных с помощью Safe Args (рекомендуется)
// В графе навигации добавляем аргумент
// <argument android:name="data" app:argType="string" />

// Фрагмент-отправитель
val action = FragmentADirections.actionFragmentAToFragmentB("Данные для передачи")
findNavController().navigate(action)

// Фрагмент-получатель
class FragmentB : Fragment() {
    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        val args: FragmentBArgs by navArgs()
        val receivedData = args.data
        textView.text = receivedData
    }
}

4. Использование SharedPreferences или базы данных

Для долговременного хранения и обмена данными между различными компонентами приложения:

// Запись данных
val prefs = requireContext().getSharedPreferences("app_data", Context.MODE_PRIVATE)
prefs.edit().putString("key", "значение").apply()

// Чтение данных
val data = prefs.getString("key", "значение по умолчанию")

5. Чрез систему событий (EventBus или LiveData)

Использование LiveData как шины событий:

// Глобальная шина событий
object EventBus {
    private val _events = MutableLiveData<Event>()
    val events: LiveData<Event> = _events
    
    fun postEvent(event: Event) {
        _events.postValue(event)
    }
}

// Отправка события
EventBus.postEvent(DataEvent("Данные для всех"))

// Подписка на события
EventBus.events.observe(viewLifecycleOwner) { event ->
    when (event) {
        is DataEvent -> handleData(event.data)
    }
}

6. Через родительский фрагмент (вложенные фрагменты)

Для вложенных фрагментов используется подход, аналогичный общению через Activity:

// Родительский фрагмент
class ParentFragment : Fragment() {
    private val viewModel: SharedViewModel by viewModels()
    
    // Дочерние фрагменты получают доступ через parentFragment
    // или через общий ViewModel с scope родительского фрагмента
}

Рекомендации по выбору подхода

  1. Для связанных фрагментов в одной Activity — используйте Shared ViewModel с scope Activity
  2. Для передачи параметров при навигацииSafe Args с Navigation Component
  3. Для слабосвязанных компонентов — система событий или SharedPreferences
  4. Для сохранения данных при повороте экрана — ViewModel + SavedStateHandle
  5. Избегайте прямых ссылок между фрагментами — это нарушает принцип инкапсуляции

Критические замечания:

  • Старый подход с setTargetFragment() и getTargetFragment() считается устаревшим и не рекомендуется
  • Прямой доступ к фрагментам через findFragmentById() или findFragmentByTag() создает жесткие зависимости
  • Глобальные шины событий (типа EventBus) могут создавать проблемы с отслеживанием потока данных и утечками памяти

Современная практика от Google рекомендует использовать ViewModel в комбинации с Navigation Component и LiveData/Flow для реактивной коммуникации между компонентами, что обеспечивает лучшую тестируемость, поддержку жизненного цикла и чистую архитектуру приложения.

Какие знаешь способы передачи данных между двумя фрагментами? | PrepBro