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

GLSurfaceView快速onPause/onResume后残留未清除帧问题求助

解决GLSurfaceView快速onPause/onResume后的帧残留问题

问题分析

快速触发onPause/onResume时,GLSurfaceView的缓冲区可能因系统窗口切换的同步机制未及时完成清空或交换操作,导致暂停前的帧被系统缓存,后续的glClear无法覆盖该缓存帧,从而出现残影。缓慢操作时系统有足够时间完成缓冲区同步,因此不会触发问题。


解决方案

1. 强制Resume后第一帧执行彻底清除

在Renderer中添加标志位,标记Resume后的第一帧,执行完整的缓冲区清除并确保操作完成:

// Renderer.kt
class MyRenderer : GLSurfaceView.Renderer {
    var isFirstFrameAfterResume = false

    override fun onDrawFrame(gl: GL10) {
        if (isFirstFrameAfterResume) {
            // 使用不透明黑色清空所有缓冲区
            gl.glClearColor(0f, 0f, 0f, 1f)
            gl.glClear(GL_COLOR_BUFFER_BIT or GL_DEPTH_BUFFER_BIT or GL_STENCIL_BUFFER_BIT)
            gl.glFinish() // 强制等待清除操作完成
            isFirstFrameAfterResume = false
            // 可选:直接返回,避免叠加绘制
            return
        }

        // 正常绘制流程
        gl.glClear(GL_COLOR_BUFFER_BIT or GL_DEPTH_BUFFER_BIT)
        // ... 你的绘制代码
    }
}

// MainActivity.kt
override fun onResume() {
    super.onResume()
    glSurfaceView.onResume()
    renderer.isFirstFrameAfterResume = true
    glSurfaceView.requestRender() // 主动触发第一帧绘制
}

2. Pause时主动清空缓冲区

在Pause阶段执行一次缓冲区清除,确保暂停前的帧被覆盖:

// Renderer.kt
fun onPause() {
    // 获取当前GL上下文(需确保调用时GL线程仍活跃)
    EGLContext.getCurrentContext()?.let { ctx ->
        val gl = GL10Impl(ctx)
        gl.glClearColor(0f, 0f, 0f, 1f)
        gl.glClear(GL_COLOR_BUFFER_BIT or GL_DEPTH_BUFFER_BIT)
        gl.glFinish()
    }
}

// MainActivity.kt
override fun onPause() {
    renderer.onPause()
    super.onPause()
    glSurfaceView.onPause()
}

3. 禁用EGL上下文保留

关闭GLSurfaceView的上下文保留功能,每次Resume时重建上下文,自动重置缓冲区:

// MainActivity.kt初始化GLSurfaceView时
glSurfaceView.setPreserveEGLContextOnPause(false)

注意:此方案会增加Resume时的上下文重建开销,适合对性能敏感度较低的场景。

4. 临时Workaround:用纯色View覆盖

在Activity中添加全屏黑色View,Pause时显示覆盖GLSurfaceView,Resume时隐藏,从视觉上消除残影:

// MainActivity.kt
override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContentView(R.layout.activity_main)
    
    val glSurfaceView = findViewById<GLSurfaceView>(R.id.gl_surface)
    // 创建覆盖View
    val coverView = View(this).apply {
        setBackgroundColor(Color.BLACK)
        visibility = View.GONE
        layoutParams = FrameLayout.LayoutParams(
            FrameLayout.LayoutParams.MATCH_PARENT,
            FrameLayout.LayoutParams.MATCH_PARENT
        )
    }
    // 添加到根布局
    (findViewById<ViewGroup>(android.R.id.content)).addView(coverView)

    // 生命周期回调
    override fun onPause() {
        super.onPause()
        coverView.visibility = View.VISIBLE
        glSurfaceView.onPause()
    }

    override fun onResume() {
        super.onResume()
        glSurfaceView.onResume()
        coverView.visibility = View.GONE
    }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.09 16:10:40