Jetpack Compose中ExoPlayer切换视频后视图不更新问题
问题分析与解决
核心问题
你的VideoPlayer组件存在两个关键问题导致视频切换失效:
exoPlayer通过remember(context)初始化,仅当context变化时才会重新创建。当videoId更新时,既不会触发播放器实例重建,也没有逻辑更新现有播放器的媒体源。AndroidView仅在首次初始化时绑定播放器,后续videoId变化时无任何更新逻辑,导致播放器内容不刷新。
解决方案(推荐复用播放器的高性能方案)
这种方式避免频繁创建销毁ExoPlayer,而是在videoId变化时动态替换媒体源:
@OptIn(UnstableApi::class) @Composable fun VideoPlayer(videoId: Int) { val context = LocalContext.current // 保留ExoPlayer实例,仅在context变化时重建(如配置变更) val exoPlayer = remember(context) { ExoPlayer.Builder(context).build() } // 监听videoId变化,更新媒体源 LaunchedEffect(videoId) { val dataSourceFactory: DataSource.Factory = DefaultDataSource.Factory(context, DefaultHttpDataSource.Factory()) val uriSource = Uri.parse( "android.resource://" + context.packageName + "/" + videoId ) val mediaItem = MediaItem.fromUri(uriSource) exoPlayer.setMediaItem(mediaItem) exoPlayer.prepare() exoPlayer.play() // 可选:切换后自动播放 } // 组件销毁时释放播放器资源,防止内存泄漏 DisposableEffect(Unit) { onDispose { exoPlayer.release() } } AndroidView( factory = { ctxt -> PlayerView(ctxt).apply { player = exoPlayer } }, // 确保videoId变化时View能关联到最新的播放器状态 update = { view -> view.player = exoPlayer } ) }
备选方案(简单直接,适合场景单一的情况)
如果你的视频切换频率不高,也可以通过将videoId加入remember依赖,让videoId变化时直接重建播放器:
@OptIn(UnstableApi::class) @Composable fun VideoPlayer(videoId: Int) { val context = LocalContext.current // videoId变化时自动重建ExoPlayer val exoPlayer = remember(videoId, context) { ExoPlayer.Builder(context).build().apply { val dataSourceFactory: DataSource.Factory = DefaultDataSource.Factory(context, DefaultHttpDataSource.Factory()) val uriSource = Uri.parse( "android.resource://" + context.packageName + "/" + videoId ) val source = ProgressiveMediaSource.Factory(dataSourceFactory) .createMediaSource(MediaItem.fromUri(uriSource)) this.setMediaSource(source) this.prepare() } } // 销毁时释放资源 DisposableEffect(Unit) { onDispose { exoPlayer.release() } } AndroidView( factory = { ctxt -> PlayerView(ctxt).apply { player = exoPlayer } } ) }
额外检查点
- 确认
VideoModel.getVideoId()返回的是正确的raw资源ID,避免取值错误导致媒体源无效。 - 若不需要自动播放,可移除
exoPlayer.play()调用。
内容的提问来源于stack exchange,提问作者Cristi
相关产品推荐
相关产品推荐

