使用queueEvent()传递渲染器和另一个类之间的变量

问题描述:

我想从另一个类传递渲染器的某些值。渲染器计算出值之后,我在助手类中有一个互斥量,它应该告诉我渲染器已经完成计算,因此我可以继续使用这些新值。我可以毫无问题地向渲染器传递值,但我无法弄清楚如何让它们回来。我目前使用一些静态变量,但在渲染器更改后,它们似乎迷路了。他们在我的其他班级中不可见。 例子:使用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。任何想法为什么?我最好的猜测是,这是因为它在另一个线程中,但我将如何解决?如果有更清洁更安全的方法,我很乐意听到他的声音。

你可以在你的活动中保持你的渲染器作为一个变量(不要像许多人那样做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