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

Composable函数可变值变更后未执行,视频无法切换求助

问题分析与解决方案

核心问题

  1. 状态更新方式错误:点击事件中直接重新赋值videoLink变量(videoLink = mutableStateOf(...)),而非修改已有MutableState的value属性,导致Composable无法感知状态变化、触发重组。
  2. DisposableEffect依赖缺失:当前DisposableEffect的参数是AndroidView实例,状态变化时不会触发重新执行,旧播放器无法被释放,新播放器也无法绑定到View。
  3. 播放器实例管理不当:每次状态变化都新建ExoPlayer实例,既浪费资源,也无法让PlayerView感知到播放器的更新。

修正后的代码

fun LiveTrainingScreen(viewModel: LiveTrainingViewModel = viewModel()) {
    Column(modifier = Modifier.padding(PaddingStatic.Small).zIndex(2f)) {
        // 用by委托简化状态管理,直接赋值即可触发重组
        var videoLink by remember { mutableStateOf(LiveTrainingViewModel.cockPitRight) }

        // 仅在videoLink变化时创建新播放器
        val exoPlayer = remember(videoLink) {
            viewModel.getCameraPlayer(videoLink).apply {
                prepare()
            }
        }

        // 以播放器为依赖,状态变化时重建View并释放旧播放器
        DisposableEffect(exoPlayer) {
            AndroidView(
                modifier = Modifier
                    .weight(1f)
                    .fillMaxSize()
                    .clip(RoundedCornerShape(RoundedSizeStatic.Medium))
                    .clickable { 
                        videoLink = LiveTrainingViewModel.mapCamera
                    },
                factory = { context ->
                    PlayerView(context).apply {
                        player = exoPlayer
                        useController = false
                        resizeMode = AspectRatioFrameLayout.RESIZE_MODE_FILL
                        layoutParams = FrameLayout.LayoutParams(
                            ViewGroup.LayoutParams.MATCH_PARENT,
                            ViewGroup.LayoutParams.MATCH_PARENT
                        )
                    }
                }
            )

            onDispose {
                exoPlayer.release()
            }
        }
    }
}

关键优化说明

  • 状态更新优化:使用var videoLink by remember { mutableStateOf(...) }的委托方式,直接通过videoLink = ...更新值,触发Composable重组。
  • 播放器实例缓存:remember(videoLink)确保仅在视频链接变化时创建新的播放器实例,避免不必要的资源消耗。
  • DisposableEffect依赖调整:将依赖设为播放器实例,确保状态变化时重建PlayerView并绑定新播放器,同时释放旧播放器资源。

进阶优化(推荐)

在ViewModel中维护单例播放器,仅更新MediaItem而非每次新建播放器,进一步提升性能:

class LiveTrainingViewModel : ViewModel() {
    private val _player = ExoPlayer.Builder(context).build()
    val player: ExoPlayer = _player

    fun updateVideoLink(link: String) {
        val mediaItem = MediaItem.fromUri(link)
        _player.setMediaItem(mediaItem)
        _player.prepare()
        _player.play()
    }
}

对应Composable简化代码:

fun LiveTrainingScreen(viewModel: LiveTrainingViewModel = viewModel()) {
    Column(modifier = Modifier.padding(PaddingStatic.Small).zIndex(2f)) {
        var videoLink by remember { mutableStateOf(LiveTrainingViewModel.cockPitRight) }

        DisposableEffect(Unit) {
            AndroidView(
                modifier = Modifier
                    .weight(1f)
                    .fillMaxSize()
                    .clip(RoundedCornerShape(RoundedSizeStatic.Medium))
                    .clickable { 
                        videoLink = LiveTrainingViewModel.mapCamera
                        viewModel.updateVideoLink(videoLink)
                    },
                factory = { context ->
                    PlayerView(context).apply {
                        player = viewModel.player
                        useController = false
                        resizeMode = AspectRatioFrameLayout.RESIZE_MODE_FILL
                        layoutParams = FrameLayout.LayoutParams(
                            ViewGroup.LayoutParams.MATCH_PARENT,
                            ViewGroup.LayoutParams.MATCH_PARENT
                        )
                    }
                }
            )

            onDispose {
                viewModel.player.release()
            }
        }
    }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.14 02:45:34