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

EXOPlayer播放VAST广告时后台重启后黑屏问题求助

解决EXOPlayer播放VAST广告后台返回黑屏的问题

核心思路

问题本质是应用进入后台时,EXOPlayer默认会释放资源、销毁播放器,导致重启后无画面。需要从播放器生命周期管理和画面留存两个方向入手解决:

1. 避免后台直接销毁播放器

修改Player的释放超时配置,延长后台保留播放器的时长,或者在特定生命周期场景下只暂停不释放:

// 初始化播放器时设置后台保留超时(示例为60秒,可按需调整)
val player = ExoPlayer.Builder(context)
    .setReleaseTimeoutMs(60000)
    .build()

// 页面生命周期中仅在销毁时释放播放器
override fun onPause() {
    super.onPause()
    player.pause() // 暂停而非释放
}

override fun onDestroy() {
    super.onDestroy()
    player.release() // 仅在页面销毁时执行释放
}

2. 留存广告最后一帧画面

即使播放器被释放,也可以在广告播放结束时捕获最后一帧,用ImageView覆盖在PlayerView上层,后台返回时先显示这张图片,待播放器就绪后再隐藏:

// 监听广告播放结束事件,捕获最后一帧
player.addListener(object : Player.Listener {
    override fun onPlaybackStateChanged(playbackState: Int) {
        if (playbackState == Player.STATE_ENDED) {
            playerView.screenshot { bitmap ->
                bitmap?.let {
                    coverImageView.setImageBitmap(it)
                    coverImageView.visibility = View.VISIBLE
                }
            }
        }
    }

    override fun onMediaItemTransition(mediaItem: MediaItem?, reason: Int) {
        // 针对广告结束的场景单独处理
        if (reason == Player.MEDIA_ITEM_TRANSITION_REASON_AD_ENDED) {
            playerView.screenshot { bitmap ->
                bitmap?.let {
                    coverImageView.setImageBitmap(it)
                    coverImageView.visibility = View.VISIBLE
                }
            }
        }
    }
})

// 后台返回时先显示覆盖图,播放器就绪后隐藏
override fun onResume() {
    super.onResume()
    coverImageView.visibility = View.VISIBLE
    player.playWhenReady = true
    player.addListener(object : Player.Listener {
        override fun onPlaybackStateChanged(playbackState: Int) {
            if (playbackState == Player.STATE_READY) {
                coverImageView.visibility = View.GONE
                player.removeListener(this)
            }
        }
    })
}

3. VAST广告专属优化

加载VAST广告时,直接使用广告自带的封面图作为PlayerView的默认占位图,避免黑屏:

val adLoader = AdLoader.Builder(context, adTagUri)
    .addVastAdListener(object : VastAdListener {
        override fun onAdLoaded(ad: Ad) {
            // 优先使用广告封面图作为占位
            ad.mediaMetadata?.artworkUri?.let { uri ->
                Glide.with(context).asBitmap().load(uri).into(object : CustomTarget<Bitmap>() {
                    override fun onResourceReady(resource: Bitmap, transition: Transition<in Bitmap>?) {
                        playerView.defaultArtwork = resource
                    }
                })
            }
        }
    })
    .build()

为什么SilenceMediaSource没生效?

SilenceMediaSource仅提供静音媒体流,无法阻止EXOPlayer在后台被系统或框架释放资源,也不能留存已播放完成的广告画面,因此解决不了核心问题。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.29 10:51:06