You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在ViewModel初始化时正确发送事件以在Activity启动后打开相机?

问题:Activity创建后通过ViewModel初始化事件启动相机失败,添加延迟才生效

需求是Activity创建完成后打开相机界面,但在ViewModel初始化函数中发送UiEvent.TakePhoto事件时,相机并未启动。仅在ViewModel初始化中添加delay(1000)后,相机才能正常启动。

相关代码

ViewModel初始化函数:

init{
  viewModelScope.launch {
    _eventFlow.emit(UiEvent.TakePhoto)
  }
}

Activity中触发相机的代码:

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)

    lifecycleScope.launch {
        lifecycle.repeatOnLifecycle(Lifecycle.State.RESUMED) {
            viewModel.eventFlow.collectLatest { event ->
                when(event){
                    is PhotoViewModel.UiEvent.TakePhoto -> takePhoto()
                }
            }
        }
    }
}

private fun takePhoto() {
    val cameraIntent = Intent(MediaStore.ACTION_IMAGE_CAPTURE)
    resultLauncher.launch(cameraIntent)
}

原因分析

问题核心是事件发射时机早于监听时机:ViewModel初始化时,Activity的lifecycle.repeatOnLifecycle(Lifecycle.State.RESUMED)块还未执行,collectLatest尚未启动监听eventFlow,导致TakePhoto事件直接丢失,没有被接收处理。添加delay(1000)只是靠延迟让Activity完成初始化、启动监听后再发射事件,属于临时 workaround,并非规范方案。

规范解决方案

方案1:在Activity就绪后通知ViewModel发射事件

不在ViewModel初始化时自动发射事件,而是等Activity生命周期就绪后,主动触发ViewModel的事件发射逻辑:

ViewModel修改:

fun triggerTakePhoto() {
    viewModelScope.launch {
        _eventFlow.emit(UiEvent.TakePhoto)
    }
}

Activity修改:

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)

    lifecycleScope.launch {
        lifecycle.repeatOnLifecycle(Lifecycle.State.RESUMED) {
            // 先启动事件监听
            viewModel.eventFlow.collectLatest { event ->
                when(event){
                    is PhotoViewModel.UiEvent.TakePhoto -> takePhoto()
                }
            }
            // 监听启动后触发相机事件
            viewModel.triggerTakePhoto()
        }
    }
}

方案2:使用SharedFlow保留事件

将eventFlow改为MutableSharedFlow并设置replay=1,它会保留最新的1个事件,后续启动的监听也能接收到之前发射的事件:

ViewModel修改:

private val _eventFlow = MutableSharedFlow<UiEvent>(replay = 1)
val eventFlow = _eventFlow.asSharedFlow()

init{
    viewModelScope.launch {
        _eventFlow.emit(UiEvent.TakePhoto)
    }
}

这种方式适合需要确保事件不丢失的场景,即使Activity启动监听较晚,也能获取到ViewModel初始化时发射的事件。

内容的提问来源于stack exchange,提问作者GrimPloughman

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.21 21:53:22