使用共享视图模型和 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()