2012-12-19 28 views
1

我正在編寫在其他線程處理Android OpenGL的程序。但是這個代碼會凍結。例如,它直接處理一個方法而不調用task.get(),如果它是相同的線程。這種方式存在嗎?如何在同一線程的情況下避免在GLSurfaceView的隊列事件

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

如果我正確地解釋你的問題,有一些代碼,你想使用FutureTaskRunnable或其他異步解決方案,而在OpenGL的線程運行。

首先,該代碼(及其任何數據)是否依賴於其他線程?是否需要與其他代碼/數據同步?如果是的話,那麼你應該從另一個線程使用queueEvent()。既然你想完全保留在OpenGL線程中,我假設你要執行的代碼與其他(非GL)線程沒有任何關係。

此外,從不會調用FutureTask.get()與應執行FutureTask代碼的線程相同 - 如果您的線程正在等待自己,誰會執行該任務?如果你想從另一個線程向GL線程發送代碼,請不要使用FutureTask;只需使用簡單的Runnable(作爲queueEvent()的參數)。

回到主要問題:要從GL線程運行一些沒有queueEvent()的東西,您應該決定您要如何執行該任務,即何時(確切地說)應該被調用。你想每次調用onDrawFrame()時都要調用它嗎?或每次調用onSurfaceChanged()onSurfaceCreated()

由於您使用了queueEvent(),我假設您希望您的代碼在下一個即將到來的onDrawFrame()調用之前運行。在Android GL線,在內部,調用的順序如下:

  1. Android的過程中你的所有排隊的事件(我簡化這一點,但主要的一點是OK)
  2. 如果需要的話,Android的電話onSurfaceCreated()
  3. 如果需要的話,Android把onSurfaceChanged()
  4. Android把onDrawFrame()

所以,把它簡單,你添加代碼10將在下一個渲染週期(onDrawFrame())之前執行。如果你想在onDrawFrame()運行GL線程上的代碼,你可以將它添加到onDrawFrame()開始,例如:

@Override 
public void onDrawFrame(GL10 gl) { 
    if (mDoJob) { 
     mDoJob = false; 

     // perform code 
    } 

    ... 
} 

這裏,mDoJobvolatile變量。您可以將其從另一個線程設置爲true但是,請注意,這裏假定您不需要與使用mDoJob信號的其他線程進行任何額外的同步,即所有將在mDoJob條件塊中運行的代碼都可以正常運行,而不會與其他任何事物進一步同步。

基本上,我上面介紹的只是一個簡化的(非同步的)解決方案來取代queueEvent(),它假設您不需要與其他線程同步(包括最新的變量)。

如果您不需要任何信號(任何與其他線程的依賴),並mDoJob的值可以在OpenGL的線程內決定(內onDrawFrame()onSurfaceCreated()onSurfaceChanged()),然後mDoJob不需要揮發。在這種情況下,您將停留在OpenGL線程中,因此不需要異步(並因此同步)的解決方案。

綜上所述,具體地講,如果你想在onSurfaceCreated()來決定代碼是否應在onDrawFrame()運行,只需使用一個(非易失性)布爾變量,你在onSurfaceCreated()設置,然後將其簽入onDrawFrame()(如在我上面的代碼示例中)。

相關問題