У вас есть Activity с двумя Fragment'ами, у одного есть кнопка, у другого TextView. При нажатии кнопки изменяется TextView. Как вы реализуете это?android-70

Для решения этой задачи нужно организовать коммуникацию между Fragment'ами. Поскольку Fragment'ы не должны общаться напрямую, мы будем использовать Activity как посредника. Вот несколько подходов:


1. Интерфейс-колбэк через Activity

Шаг 1: Создаем интерфейс в Fragment'е с кнопкой

class ButtonFragment : Fragment() {
    // Объявляем интерфейс для коммуникации с Activity
    interface OnButtonClickListener {
        fun onButtonClicked(newText: String)
    }

    private var listener: OnButtonClickListener? = null

    override fun onAttach(context: Context) {
        super.onAttach(context)
        listener = context as? OnButtonClickListener
    }

    override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
        val view = inflater.inflate(R.layout.fragment_button, container, false)
        view.findViewById<Button>(R.id.button).setOnClickListener {
            listener?.onButtonClicked("Новый текст")
        }
        return view
    }

    override fun onDetach() {
        super.onDetach()
        listener = null
    }
}

Шаг 2: Реализуем интерфейс в Activity

class HostActivity : AppCompatActivity(), ButtonFragment.OnButtonClickListener {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_host)
    }

    override fun onButtonClicked(newText: String) {
        val textFragment = supportFragmentManager.findFragmentById(R.id.text_fragment) as? TextFragment
        textFragment?.updateText(newText)
    }
}

Шаг 3: Добавляем метод в Fragment с TextView

class TextFragment : Fragment() {
    fun updateText(newText: String) {
        view?.findViewById<TextView>(R.id.text_view)?.text = newText
    }
}

2. ViewModel + Shared ViewModel

Для более сложных случаев можно использовать Shared ViewModel:

Шаг 1: Создаем Shared ViewModel

class SharedViewModel : ViewModel() {
    val textLiveData = MutableLiveData<String>()
}

Шаг 2: Настраиваем Fragment с кнопкой

class ButtonFragment : Fragment() {
    private val viewModel: SharedViewModel by activityViewModels()

    override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
        val view = inflater.inflate(R.layout.fragment_button, container, false)
        view.findViewById<Button>(R.id.button).setOnClickListener {
            viewModel.textLiveData.value = "Новый текст из ViewModel"
        }
        return view
    }
}

Шаг 3: Настраиваем Fragment с TextView

class TextFragment : Fragment() {
    private val viewModel: SharedViewModel by activityViewModels()

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        viewModel.textLiveData.observe(viewLifecycleOwner) { newText ->
            view.findViewById<TextView>(R.id.text_view).text = newText
        }
    }
}

3. Прямой доступ через Activity

// В ButtonFragment
(activity as? HostActivity)?.updateTextInFragment("Текст")

// В Activity
fun updateTextInFragment(newText: String) {
    (supportFragmentManager.findFragmentById(R.id.text_fragment) as? TextFragment)?.updateText(newText)
}

Сравнение подходов

Способ Плюсы Минусы
ИнтерфейсЧистая архитектура, тестируемостьБольше кода
Shared ViewModelПодходит для сложных сценариевИзбыточен для простых случаев
Прямой доступПростотаНарушает инкапсуляцию


Важные нюансы

  1. Всегда проверяйте isAdded перед обновлением UI во Fragment'ах.
  2. Для Shared ViewModel используйте activityViewModels() вместо viewModels().
  3. Учитывайте жизненный цикл Fragment'ов при обновлении данных.

Резюмируем:

Лучший способ - использование интерфейса через Activity для простых случаев или Shared ViewModel для более сложных сценариев. Это обеспечивает чистую архитектуру и правильное разделение ответственности между компонентами.