2011-12-07 55 views
11

我想從另一個類傳遞渲染器的某些值。渲染器計算出值之後,我在助手類中有一個互斥量,它應該告訴我渲染器已經完成計算,因此我可以繼續使用這些新值。我可以毫無問題地向渲染器傳遞值,但我無法弄清楚如何讓它們回來。我目前使用一些靜態變量,但在渲染器更改後,它們似乎迷路了。他們在我的其他班級中不可見。 例子:使用queueEvent()傳遞渲染器和另一個類之間的變量

public class View extends SurfaceView{ 

    private void doSomething(){ 

    glSurfaceView.queueEvent(new Runnable() { 

       @Override 
       public void run() { 
        //.. 
        renderer.calculate(stack);  
       } 
    }); 
    } 

private void doAnotherThing(){ 

    //Never happens: 
    if(Helper.hasCalculated){ 
    /... 
    } 
} 

}

在我的渲染

public class MyRenderer implements GLSurfaceView.Renderer{ 

    private void calculate(Stack stack){   
     Helper.hasCalculated = true 
    } 
} 

我的助手類:

public class Helper{ 

public static volatile boolean hasCalculated = false; 

} 

hasCalculated在渲染器中肯定設置爲true,但我的其他類始終將其視爲false。任何想法爲什麼?我最好的猜測是,這是因爲它在另一個線程中,但我將如何解決?如果有更清潔更安全的方法,我很樂意聽到他的聲音。

回答

14

你可以在你的活動中保持你的渲染器作爲一個變量(不要像許多人那樣做mGLView.setRenderer(new MyRenderer());,而是MyRenderer myRenderer = new MyRenderer(); mGLView.setRenderer(myRenderer);)。然後,您可以通過方法調用輕鬆地與您的渲染器通信。那麼問題就出現在跨線程通信上。我在下面提供了兩個示例,一個是非UI線程,GL線程和主UI線程之間的通信。第二個例子是隻爲GL線程和UI線程之間的通信

public class Test3D extends Activity{ 

private MyRenderer renderer; // keep hold of the renderer as a variable in activity 
private MyAsyncTask gameLoop; 

/** Called when the activity is first created. */ 
@Override 
public void onCreate(Bundle savedInstanceState) { 
    super.onCreate(savedInstanceState); 

    setContentView(R.layout.main); 

    myRenderer = new MyRenderer(); // create the renderer object 

    GLSurfaceView mGLView = (GLSurfaceView)findViewById(R.id.glsurfaceview1); 
    mGLView.setEGLConfigChooser(true); 
    mGLView.setRenderer(myRenderer); // set the surfaceView to use the renderer 

    gameLoop = new MyAsyncTask(); 
    gameLoop.execute(); // start a new, non-UI, thread to do something 

} 

/// non-UI thread (inner class of my Test3D activity) 
class MyAsyncTask extends AsyncTask<Void, Void, Void>{ 

    @Override 
    protected Void doInBackground(Void... arg0) { 

      myRenderer.startCalc(); // tell renderer to start calculation 

      while(!myRenderer.isFinishedCalc()){ 

       // waiting for calc to finish, but not blocking UI thread 

       try { 
        long x = 1000; 
        Thread.sleep(x); 
        // sleep the thread for x amount of time to save cpu cycles 
       } catch (InterruptedException e) { 
        // TODO Auto-generated catch block 
        e.printStackTrace(); 
       } 

      } 

      publishProgress(null); 
      // when calculation has finished, we will drop out of the loop 
      // and update the UI 



    } 

    protected void onProgressUpdate(Void... progress) {   
     // update UI 
    } 


} 


} 

然後在渲染

public class MyRenderer implements Renderer{ 

    private boolean startCalc = false; 
    private boolean finishCalc = false; 

    public void startCalc(){ 
     finishCalc = false; 
     startCalc = true; 
    } 

    public boolean isFinishedCalc(){ 
     return finishCalc; 
    } 

    public void onDraw(GL10 gl){ 

     if(startCalc){ 
      // do calculation using GL handle 
      // always performed in the GL thread 

      finishCalc = true; 
      startCalc = false; 
     } 

     // draw 

    } 



} 

我在上面的渲染器示例中使用的標誌,但它是相當簡單的把如果你想告訴渲染器「加載這個模型陣列」,那麼進入隊列。既然你已經使用GL手柄加載模型(或至少紋理)在GL線程,你可以有其他類和線程做你的邏輯和剛纔的GL東西在GL線程



完成或者,如果你只是想你計算完成後更新UI線程,而不是任何其他線程交互:從任何地方

public class MyRenderer implements Renderer{ 

    private Handler handler = null; 
    public static final int CALC_FINISHED = 1; 

    public void startCalc(Handler handler){ 
     this.handler = handler; 
    } 

    public void onDraw(GL10 gl){ 

     if(handler!=null){ 
      // do calculation using GL handle 
      int flag = MyRenderer.CALC_FINISHED; 
      handler.dispatchMessage(Message.obtain(handler, flag)); 
      // adds a message to the UI thread's message queue 

      handler = null; 

     } 

     // draw 

    } 

} 

然後:

myRenderer.startCalc(new Handler(){ 

    public void handleMessage (Message msg){ 

     if(msg.what==MyRenderer.CALC_FINISHED){ 
      // Update UI 
      // this code will always be executed in the UI thread 

     } 

    } 

}); 
+0

哇,謝謝。明天當我回去工作時,我會仔細看看。 – Lennart