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

Jetpack Compose中ExoPlayer PlayerView返回时UI泄漏问题求助

Jetpack Compose中ExoPlayer PlayerView返回时残留/泄漏问题

在Jetpack Compose页面中使用ExoPlayer的PlayerView时,按下返回键或调用navController.popBackStack()返回上一屏,PlayerView会残留到上一屏,几秒后才消失。

问题页面代码

@OptIn(ExperimentalMaterialApi::class)
@Stateless
@Composable
fun HelpVideo(@RawRes videoResource: Int,onNavIconClicked: () -> Unit,@StringRes guideTitle: Int) 
{
ApplyStatusNavBarColor()
MaintenanceAppScaffold(topAppBar = {
    CommonAppBar(
        text = R.string.soundassist_update_interrupted_video,
        isInfoButton = false,
        isBackButton = false
    )
})
{
    val context = LocalContext.current

    val exoPlayer = remember {
        ExoPlayer.Builder(context).build().apply {
            val videoUri = RawResourceDataSource.buildRawResourceUri(videoResource)
            val mediaItem = MediaItem.fromUri(videoUri)
            addMediaItem(mediaItem)
            prepare()
            playWhenReady = true
        }
    }
    LaunchedEffect(exoPlayer) {
        exoPlayer.awaitVideoFinish()
        onNavIconClicked()
    }
    AndroidView(
        modifier =
        Modifier.fillMaxSize(),
        factory = {
            StyledPlayerView(context).apply {
                player = exoPlayer
                layoutParams =
                    FrameLayout.LayoutParams(
                        ViewGroup.LayoutParams
                            .MATCH_PARENT,
                        ViewGroup.LayoutParams
                            .MATCH_PARENT
                    )
                useController = false
            }
        }
    )

    DisposableEffect(exoPlayer) {
        onDispose {
            exoPlayer.release()
        }
    }
}}

问题详情

返回上一屏时:

  • 无论按下返回键还是调用navController.popBackStack(),PlayerView都会在上一屏显示几秒后才消失。

已尝试方案

  • 使用navController.popBackStack()——问题依旧存在。
  • 临时方案:调用navController.navigate(GoToPreviousScreen),但引发其他导航问题,非理想解决方式。

疑问与需求

为何返回时PlayerView会出现这种行为?如何在保留正确导航行为、避免navigate()这类临时方案的前提下修复该问题?

附加信息

使用Jetpack Compose搭配ExoPlayer进行视频播放,问题似乎与AndroidView中PlayerView的生命周期或销毁逻辑相关。
PlayerView残留问题展示


问题原因分析

这个问题的核心是AndroidView的销毁时机与ExoPlayer的释放逻辑不匹配,结合Compose导航的视图切换机制共同导致:

  1. Compose执行popBackStack()时,当前可组合项不会立即从视图树移除,需经历重组和视图销毁流程,存在延迟。
  2. PlayerView作为原生View,其Surface渲染层级独立于Compose视图树,即便Composable标记为销毁,原生Surface可能仍短暂保留在Window中,直到ExoPlayer完全释放或View被彻底detach。
  3. 当前代码仅在DisposableEffect中释放ExoPlayer,未明确处理PlayerView与Player的解绑、PlayerView的销毁逻辑,导致视图残留。

修复方案

方案1:在AndroidView中处理销毁时的解绑与移除

通过AndroidView的update块,监听Composable的销毁状态,主动解绑Player并从父布局移除PlayerView:

AndroidView(
    modifier = Modifier.fillMaxSize(),
    factory = {
        StyledPlayerView(context).apply {
            player = exoPlayer
            layoutParams = FrameLayout.LayoutParams(
                ViewGroup.LayoutParams.MATCH_PARENT,
                ViewGroup.LayoutParams.MATCH_PARENT
            )
            useController = false
        }
    },
    update = { playerView ->
        // 检测当前Composable是否即将销毁
        val isDisposed = !currentComposer.currentRecomposeScope.isValid
        if (isDisposed) {
            playerView.player = null
            // 从父布局移除PlayerView
            (playerView.parent as? ViewGroup)?.removeView(playerView)
        }
    }
)

方案2:优化DisposableEffect的释放逻辑

在DisposableEffect的onDispose中,先停止播放、解绑Player,再释放ExoPlayer,确保资源清理顺序:

DisposableEffect(exoPlayer) {
    onDispose {
        exoPlayer.stop()
        // 解绑PlayerView与Player
        (exoPlayer.view as? StyledPlayerView)?.player = null
        exoPlayer.release()
    }
}

方案3:结合生命周期感知提前清理

利用LocalLifecycleOwner监听页面生命周期,在页面进入DESTROYED状态时立即处理资源:

val lifecycleOwner = LocalLifecycleOwner.current
LaunchedEffect(lifecycleOwner) {
    lifecycleOwner.lifecycle.repeatOnLifecycle(Lifecycle.State.DESTROYED) {
        exoPlayer.stop()
        (exoPlayer.view as? StyledPlayerView)?.player = null
        exoPlayer.release()
    }
}

额外优化建议

  • 避免依赖awaitVideoFinish()触发导航的逻辑,视频播放完成后直接调用navController.popBackStack()返回,减少生命周期冲突。
  • 确保onNavIconClicked()内部是执行popBackStack()而非navigate(),避免额外的导航栈问题。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.14 20:26:17