在同一个线程的情况下,如何避免GLSurfaceView中的queueEvent

时间:2012-12-19 06:52:55

标签: android opengl-es glsurfaceview

我正在编写在其他线程处理Android OpenGL的程序。但是在这个代码的情况下它冻结了。例如,它直接处理方法而不调用task.get(),如果它是相同的线程。这种方式存在吗?

public void onSurfaceCreated(GL10 arg0, EGLConfig arg1)
{
    Thread t = new Thread(new Runnable(){
        @Override
        public void run()
        {
            FutureTask<Object> task = new FutureTask<Object>(new Callable<Object>() {
                @Override
                public Object call() {
                    return null;
                }
            });
            gv.queueEvent(task);
            try{
                task.get();
            }catch(Exception e){

            }
            Log.i("MainActivity", "Done");    // <- Work
        }
    });
    t.start();

    FutureTask<Object> task = new FutureTask<Object>(new Callable<Object>() {
        @Override
        public Object call() {
            return null;
        }
    });
    gv.queueEvent(task);
    try{ task.get(); }catch(Exception e){}    // <- Freeze
    Log.i("MainActivity", "Done");

1 个答案:

答案 0 :(得分:1)

如果我正确地解释了您的问题,那么您希望在OpenGL线程中使用FutureTaskRunnable或其他异步解决方案运行一些代码。< / p>

首先,此代码(及其任何数据)是否依赖于其他线程?是否需要与其他代码/数据同步?如果是,那么您应该使用来自不同线程的queueEvent()。由于您希望完全保留在OpenGL线程中,我假设您要执行的代码与其他(非GL)线程没有任何关系。

此外,永远不要从与应该执行FutureTask.get()代码的线程相同的线程中调用FutureTask - 如果您的线程在等待自己,谁将执行该工作?如果您想从另一个线程向GL线程发送代码,请不要使用FutureTask;只需使用简单的Runnable(作为queueEvent()的参数)。

回到主要问题:要在不使用queueEvent()的情况下从GL线程运行某些内容,您应该确定要执行该作业的确切程度,即何时(何时)应该调用它。你想在每次调用onDrawFrame()时调用它吗?或者每次调用onSurfaceChanged()onSurfaceCreated()

由于您使用了queueEvent(),我认为您希望代码在下一次即将进行的onDrawFrame()调用之前运行。在Android GL线程中,内部调用顺序如下:

  1. Android处理所有排队的事件(我简化了一下,但重点是确定)
  2. 如果需要,Android会调用onSurfaceCreated()
  3. 如果需要,Android会调用onSurfaceChanged()
  4. Android调用onDrawFrame()
  5. 因此,简单来说,使用queueEvent()添加的代码将在下一个渲染周期(onDrawFrame())之前执行。如果要在onDrawFrame()中的GL主题上运行此代码,可以将其添加到onDrawFrame()的开头,例如:

    @Override
    public void onDrawFrame(GL10 gl) {
        if (mDoJob) {
            mDoJob = false;
    
            // perform code
        }
    
        ...
    }
    

    此处,mDoJobvolatile变量。您可以从另一个线程将其设置为true但是,请注意这假设您不需要与使用mDoJob信号的其他线程进行任何其他同步,即所有将在{{1}中运行的代码条件块将没有任何进一步与其他任何同步。

    基本上,我上面介绍的只是一个简化的(非同步)解决方案来替换mDoJob,它假定您不需要与其他线程同步(包括最新的变量)。

    如果您不需要任何信令(任何依赖于其他线程),并且queueEvent()的值可以在OpenGL线程内部决定(在mDoJob内,onDrawFrame()或{ {1}}),然后onSurfaceCreated()不需要是易变的。在这种情况下,您将保留在OpenGL线程中,因此不需要异步(并因此同步)的解决方案。

    总而言之,如果您想在onSurfaceChanged()中决定代码是否应该在mDoJob中运行,请使用您在{{1}中设置的(非易失性)布尔变量然后在onSurfaceCreated()中检查它(如上面的代码示例中所示)。