2011-12-07 10 views
11

Quiero pasar algunos valores de mi clase a mi representador. Después de que el procesador haya calculado los valores, tengo un mutex en una clase de ayuda que debería decirme que el renderizador ha terminado de calcular para poder continuar con estos nuevos valores. Puedo pasar los valores del renderizador sin problemas, pero no puedo encontrar la manera de recuperarlos. Actualmente uso algunas variables estáticas, pero después de que el representador las modifique, parecen perderse. No son visibles en mi otra clase. Ejemplo:Pasar variables entre el renderizador y otra clase con queueEvent()

Una clase

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){ 
    /... 
    } 
} 

}

En mi procesador de:

public class MyRenderer implements GLSurfaceView.Renderer{ 

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

Mi clase de ayuda:

public class Helper{ 

public static volatile boolean hasCalculated = false; 

} 

hasCalculated definitivamente se establece en true en el renderizador, pero mi otra clase siempre lo ve como falso. ¿Alguna idea de por qué? Mi mejor suposición es que es porque está en otro hilo, pero ¿cómo lo resolvería? Si hay un enfoque más limpio y seguro, estaría feliz de escucharlo.

Respuesta

14

Puede mantener su operador como una variable en su actividad (no solo haga mGLView.setRenderer(new MyRenderer()); como mucha gente lo hace, sino más bien MyRenderer myRenderer = new MyRenderer(); mGLView.setRenderer(myRenderer);). Entonces puede comunicarse con su procesador fácilmente a través de llamadas a métodos. El problema simplemente se reduce a la comunicación entre hilos. He puesto dos ejemplos a continuación, uno con comunicación entre un hilo no UI, el hilo GL y el hilo principal de UI. El segundo ejemplo es sólo para la comunicación entre el hilo y el hilo de interfaz de usuario GL

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 
    } 


} 


} 

Luego, en renderizador

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 

    } 



} 

He usado banderas en el ejemplo anterior render, pero sería bastante simple para convertir que en una cola, si, por ejemplo, quería decirle al procesador "cargar esta matriz de modelos". Ya que tienes que cargar los modelos (o al menos texturas) en la rosca GL usando el mango GL, puede tener otras clases y las discusiones hacen su lógica y acaban las cosas GL hecho en la rosca GL



Como alternativa, si sólo desea actualizar el hilo de interfaz de usuario después de que su cálculo se realiza, en lugar de interactuar con otros hilos:

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 

    } 

} 

y desde cualquier lugar:

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

Wow, gracias. Tendré una mirada más cercana mañana cuando regrese al trabajo. – Lennart

Cuestiones relacionadas