我正在编写在其他线程处理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");
答案 0 :(得分:1)
如果我正确地解释了您的问题,那么您希望在OpenGL线程中使用FutureTask
,Runnable
或其他异步解决方案运行一些代码。< / p>
首先,此代码(及其任何数据)是否依赖于其他线程?是否需要与其他代码/数据同步?如果是,那么您应该使用来自不同线程的queueEvent()
。由于您希望完全保留在OpenGL线程中,我假设您要执行的代码与其他(非GL)线程没有任何关系。
此外,永远不要从与应该执行FutureTask.get()
代码的线程相同的线程中调用FutureTask
- 如果您的线程在等待自己,谁将执行该工作?如果您想从另一个线程向GL线程发送代码,请不要使用FutureTask
;只需使用简单的Runnable
(作为queueEvent()
的参数)。
回到主要问题:要在不使用queueEvent()
的情况下从GL线程运行某些内容,您应该确定要执行该作业的确切程度,即何时(何时)应该调用它。你想在每次调用onDrawFrame()
时调用它吗?或者每次调用onSurfaceChanged()
或onSurfaceCreated()
?
由于您使用了queueEvent()
,我认为您希望代码在下一次即将进行的onDrawFrame()
调用之前运行。在Android GL线程中,内部调用顺序如下:
onSurfaceCreated()
onSurfaceChanged()
onDrawFrame()
因此,简单来说,使用queueEvent()
添加的代码将在下一个渲染周期(onDrawFrame()
)之前执行。如果要在onDrawFrame()
中的GL主题上运行此代码,可以将其添加到onDrawFrame()
的开头,例如:
@Override
public void onDrawFrame(GL10 gl) {
if (mDoJob) {
mDoJob = false;
// perform code
}
...
}
此处,mDoJob
是volatile
变量。您可以从另一个线程将其设置为true
。 但是,请注意这假设您不需要与使用mDoJob
信号的其他线程进行任何其他同步,即所有将在{{1}中运行的代码条件块将没有任何进一步与其他任何同步。
基本上,我上面介绍的只是一个简化的(非同步)解决方案来替换mDoJob
,它假定您不需要与其他线程同步(包括最新的变量)。
如果您不需要任何信令(任何依赖于其他线程),并且queueEvent()
的值可以在OpenGL线程内部决定(在mDoJob
内,onDrawFrame()
或{ {1}}),然后onSurfaceCreated()
不需要是易变的。在这种情况下,您将保留在OpenGL线程中,因此不需要异步(并因此同步)的解决方案。
总而言之,如果您想在onSurfaceChanged()
中决定代码是否应该在mDoJob
中运行,请使用您在{{1}中设置的(非易失性)布尔变量然后在onSurfaceCreated()
中检查它(如上面的代码示例中所示)。