调整大小和恢复/暂停 GLSurfaceView 时出现问题

fru*_*mle 9 lifecycle android opengl-es glsurfaceview

GLSurfaceView在我的应用程序中使用,最近在调整它的大小时发现了一个奇怪的行为。最后,我找出了导致我的应用程序出现问题的原因,并创建了一个简单的示例来重现它。

假设我们有一个FrameLayout包含 simple GLSurfaceView. 在每次点击时,GLSurfaceView我们使用以下代码更改其高度

CyclicIterator<Integer> iterator = CyclicIterator.from(200, 300, 500);
glView.setOnClickListener(v -> {
    glView.getLayoutParams().height = sizeIterator.next();
    glView.requestLayout();
});
Run Code Online (Sandbox Code Playgroud)

一切顺利,直到我们在后台快速移动应用程序,然后使用“概览”按钮(类似于“猴子测试”)返回到前台。如果我们足够快地在背景/前景之间切换并再次调整视图大小,我们最终可能会遇到以下情况:表面内出现一个“死”区域,直到我们再次停止/开始活动它才会更新。

glGetError在每次 gl 调用后都检查过,没有收到任何错误。同时我收到了正确的widthheightonSurfaceChanged回调。

我尝试重现此行为并在 Nexus 5X 和小米红米 6A 上获得相同的结果。

更多细节

GLSurfaceView 配置为:

glView.setEGLContextClientVersion(2);
glView.setRenderer(new Renderer() {
    @Override
    public void onSurfaceCreated(GL10 gl, EGLConfig config) {
        gl.glClearColor(1.0f, 0.0f, 0.0f, 1.0f);
    }

    @Override
    public void onSurfaceChanged(GL10 gl, int width, int height) {
        gl.glViewport(0, 0, width, height);
    }

    @Override
    public void onDrawFrame(GL10 gl) {
        gl.glClear(GLES20.GL_COLOR_BUFFER_BIT);
    }
});
glView.setRenderMode(GLSurfaceView.RENDERMODE_WHEN_DIRTY);
Run Code Online (Sandbox Code Playgroud)

正如官方文档所说,我们应该通知GLSurfaceView生命周期事件:

@Override
protected void onStart() {
    super.onStart();
    glView.onResume();
}

@Override
protected void onStop() {
    glView.onPause();
    super.onStop();
}
Run Code Online (Sandbox Code Playgroud)

然而,在实际应用中,当我们的应用进入后台时,我们还需要保存首选项并释放一些资源和服务(参见 Google 的相机示例)。正如我发现的,正是这些调用导致了GLSurfaceView我的应用程序中的故障,所以我通过以下方式模拟了它们:

@Override
protected void onResume() {
    super.onResume();

    // Simulate such actions as e.g.:
    // restorePreferences();
    // startCameraThread();
    // openCamera();

    synchronized (this){
        try{
            this.wait(400);
        }catch (InterruptedException ie){
            ie.printStackTrace();
        }
    }
}

@Override
protected void onPause() {

    // Simulate such actions as e.g.:
    // releaseCamera();
    // stopCameraThread();
    // savePreferences();

    synchronized (this){
        try{
            this.wait(400);
        }catch (InterruptedException ie){
            ie.printStackTrace();
        }
    }

    super.onPause();
}
Run Code Online (Sandbox Code Playgroud)

脏溶液

我发现可以通过将GLSurfaceView的可见性切换到GONE和返回VISIBLEin来修复此故障onResume

@Override
protected void onResume() {
    super.onResume();
    //...
    glView.setVisibility(View.GONE);
    glView.setVisibility(View.VISIBLE);
    //...
}
Run Code Online (Sandbox Code Playgroud)

但是,这显然不是我正在寻找的解决方案,所以

概括

我是否错过了一些重要的工作GLSurfaceView,或者它只是其实现中的一个错误?