Composable函数可变值变更后未执行,视频无法切换求助
问题分析与解决方案
核心问题
- 状态更新方式错误:点击事件中直接重新赋值
videoLink变量(videoLink = mutableStateOf(...)),而非修改已有MutableState的value属性,导致Composable无法感知状态变化、触发重组。 - DisposableEffect依赖缺失:当前
DisposableEffect的参数是AndroidView实例,状态变化时不会触发重新执行,旧播放器无法被释放,新播放器也无法绑定到View。 - 播放器实例管理不当:每次状态变化都新建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
相关产品推荐
相关产品推荐

