Отправка данных между фрагментами с использованием общей модели представления и SharedFlow

#android #kotlin #kotlin-flow

#Android #котлин #котлин-поток

Вопрос:

Я очень новичок в потоках Котлина. Как следует из названия, у меня в основном есть 2 фрагмента, которые разделяют модель представления. Я хочу отправлять данные между ними, используя SharedFlow в качестве замены LiveData, не сохраняя его состояние.

Фрагмент А

 class FragmentA: Fragment() {  private lateinit var viewModelShared: SharedViewModel  //Others//  override fun onViewCreated(view: View, savedInstanceState: Bundle?) {  super.onViewCreated(view, savedInstanceState)  viewModelShared = ViewModelProvider(requireActivity())[SharedViewModel::class.java]    someView.setOnClickListener{  viewModelShared.sendData("Hello")}  //Fragment Navigates From Fragment A to B using NavController  navController.navigate(some_action_id)  }   }  

Фрагмент В

 class FragmentB: Fragment() {  private lateinit var viewModelShared: SharedViewModel  //Others//  override fun onViewCreated(view: View, savedInstanceState: Bundle?) {  super.onViewCreated(view, savedInstanceState)  viewModelShared = ViewModelProvider(requireActivity())[SharedViewModel::class.java]    lifecycleScope.launchWhenCreated {  viewModelMain.sharedFlow.collectLatest {  //Data or the word 'Hello' sent from Fragment A not being Received Here   }  }   }  

Модель SharedViewModel

 class SharedViewModel:ViewModel() {  private val _sharedFlow= MutableSharedFlowlt;Stringgt;()  val sharedFlow= _sharedFlow.asSharedFlow()    fun sendData(data:String){ viewModelScope.launch {  _sharedFlow.emit(data) } }    }  

Ответ №1:

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

Однако, поскольку у вашего SharedFlow нет истории воспроизведения, это означает, что фрагменту B нечего собирать, когда он снова появится на экране. Предположительно, он находится за пределами экрана, когда FragmentA обновляет поток.

Таким образом, ваш общий поток без воспроизведения не имеет никакого отношения к тому, что в настоящее время у него нет коллекторов, и полученное значение выбрасывается. Чтобы это сработало, вам нужно повторить хотя бы 1 раз.

 private val _sharedFlow= MutableSharedFlowlt;Stringgt;(replay = 1)  

Вы упомянули «без сохранения его состояния», но это невозможно без состояния, если два фрагмента не отображаются на экране одновременно.

Кстати, есть более простой способ объявить вашу общую модель представления:

 private val viewModelShared: SharedViewModel by activityViewModels()  

Комментарии:

1. Большое вам спасибо, теперь это работает! Когда я сказал «сохранение его состояния», я имел в виду сохранение значения в n раз до тех пор, пока оно наблюдается. Извините за путаницу по этому поводу. Потоки Котлина действительно новы для меня, выглядят гибкими, но за счет кривой обучения по сравнению с LiveData, ха-ха.