使用共享视图模型和 SharedFlow 在片段之间发送数据
Sending Data between Fragments using Shared Viewmodel and SharedFlow
我对 Kotlin Flows 还很陌生。正如标题所示,我基本上有 2 个共享 ViewModel 的片段。我想使用 SharedFlow 代替 LiveData 在它们之间发送数据而不保留它的状态。
片段A
class FragmentA: Fragment() {
private lateinit var viewModelShared: SharedViewModel
//Others//
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
uper.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)
}
}
}
片段 B
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= MutableSharedFlow<String>()
val sharedFlow= _sharedFlow.asSharedFlow()
fun sendData(data:String){
viewModelScope.launch {
_sharedFlow.emit(data)
}
}
}
您的 FragmentB 仅在处于启动状态或更高状态时才收集。这是正确的,因为您不希望在视图不可见且当前可能没有视图时使用视图。
但是,由于您的 SharedFlow 没有重播历史记录,这意味着当 FragmentB 返回屏幕时,没有任何内容可供 FragmentB 收集。大概是 FragmentA 更新流程时它在屏幕外。
因此,没有重放的 SharedFlow 在当前没有收集器时无事可做,发出的值将被丢弃。您需要至少重播 1 次才能正常工作。
private val _sharedFlow= MutableSharedFlow<String>(replay = 1)
您提到了“不保留其状态”,但如果两个片段不同时出现在屏幕上,则没有状态是不可能的。
顺便说一句,有一种更简单的方法来声明您的共享 ViewModel:
private val viewModelShared: SharedViewModel by activityViewModels()
我对 Kotlin Flows 还很陌生。正如标题所示,我基本上有 2 个共享 ViewModel 的片段。我想使用 SharedFlow 代替 LiveData 在它们之间发送数据而不保留它的状态。
片段A
class FragmentA: Fragment() {
private lateinit var viewModelShared: SharedViewModel
//Others//
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
uper.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)
}
}
}
片段 B
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= MutableSharedFlow<String>()
val sharedFlow= _sharedFlow.asSharedFlow()
fun sendData(data:String){
viewModelScope.launch {
_sharedFlow.emit(data)
}
}
}
您的 FragmentB 仅在处于启动状态或更高状态时才收集。这是正确的,因为您不希望在视图不可见且当前可能没有视图时使用视图。
但是,由于您的 SharedFlow 没有重播历史记录,这意味着当 FragmentB 返回屏幕时,没有任何内容可供 FragmentB 收集。大概是 FragmentA 更新流程时它在屏幕外。
因此,没有重放的 SharedFlow 在当前没有收集器时无事可做,发出的值将被丢弃。您需要至少重播 1 次才能正常工作。
private val _sharedFlow= MutableSharedFlow<String>(replay = 1)
您提到了“不保留其状态”,但如果两个片段不同时出现在屏幕上,则没有状态是不可能的。
顺便说一句,有一种更简单的方法来声明您的共享 ViewModel:
private val viewModelShared: SharedViewModel by activityViewModels()