首页 > 解决方案 > Android OpenGL:GLSurfaceView.Renderer.onDrawFrame() 在启动时调用了两次

问题描述

我有一个使用 OpenGL 的简单 Android 应用程序(通过GLSurfaceView)。代码如下:

public class MainActivity extends Activity {
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(new MyGLSurfaceView(this));
    }

    class MyGLSurfaceView extends GLSurfaceView implements GLSurfaceView.Renderer {
        MyGLSurfaceView(Context context) {
            super(context);
            setEGLContextClientVersion(2);        // OpenGL ES 2.0
            setRenderer(this);                    // callbacks go to this class
            setRenderMode(RENDERMODE_WHEN_DIRTY); // draw on request
        }

        public void onSurfaceChanged(GL10 gl, int width, int height) { }

        public void onSurfaceCreated(GL10 gl, EGLConfig config) { }

        public void onDrawFrame(GL10 gl) {
            /* if (startup) do_only_once(); */
            try { Thread.sleep(250); } catch (Exception ignored) { }
        }
    }
}

在应用程序启动时onDrawFrame()GLSurfaceView.Renderer大多数时候调用了两次。据我所知,onSurfaceChanged()GLSurfaceView.Renderer)应该调用onDrawFrame(),但我不明白为什么它会发生多次。

我想计算和绘制一些“背景”对象,应该只做一次。我使用setRenderMode(RENDERMODE_WHEN_DIRTY)。但是onDrawFrame()仍然被调用了几次。我怎样才能让它只被调用一次?这种重复调用的原因是什么?

在每个函数的开头和结尾为这些函数(以及一些默认的Activity回调)添加日志记录将导致下面的输出。活动生命周期似乎工作正常:

// Example of function with Logging:
protected void onCreate(Bundle savedInstanceState) {
    Log.d("__DEBUG__", "onCreate() {");
    super.onCreate(savedInstanceState);
    setContentView(new MyGLSurfaceView(this));
    Log.d("__DEBUG__", "onCreate() }");
}

22:12:46.361 __DEBUG__: onCreate() {
22:12:46.376 __DEBUG__: MyGLSurfaceView() {
22:12:46.376 __DEBUG__: MyGLSurfaceView() }
22:12:46.430 __DEBUG__: onCreate() }
22:12:46.431 __DEBUG__: onStart() {
22:12:46.431 __DEBUG__: onStart() }
22:12:46.432 __DEBUG__: onResume() {
22:12:46.433 __DEBUG__: onResume() }
22:12:46.498 __DEBUG__: onSurfaceCreated() {
22:12:46.498 __DEBUG__: onSurfaceCreated() }
22:12:46.498 __DEBUG__: onSurfaceChanged() {
22:12:46.498 __DEBUG__: onSurfaceChanged() }
22:12:46.498 __DEBUG__: onDrawFrame() {
22:12:46.748 __DEBUG__: onDrawFrame() }
22:12:46.754 __DEBUG__: onDrawFrame() {
22:12:47.004 __DEBUG__: onDrawFrame() }

标签: androidopengl-esglsurfaceview

解决方案


我研究了GLSurfaceView的平台代码,发现onDrawFrame()可以触发两次,其中一次在 ctor 中。

我创建了一个带有建议修复的 AOSP 合并请求,可以在此处找到:https ://android-review.googlesource.com/c/platform/frameworks/base/+/858050 。然而,考虑到可能的风险,它被“拒绝”了,因为它不是太重要......

处理这个问题的唯一方法是在onDrawFrame()内部实现带有 switch-case 的简单状态机。需要保持“初始”状态并重绘初始元素(在我的情况下为背景),直到真正的绘制请求到来(第一个请求将状态机切换到“正常”状态)。


推荐阅读