2011-12-07 27 views
11

Tôi muốn chuyển trình kết xuất của mình một số giá trị từ một lớp khác. Sau khi trình kết xuất đã tính toán các giá trị, tôi có một mutex trong một lớp trợ giúp sẽ cho tôi biết rằng trình kết xuất đã hoàn thành việc tính toán để tôi có thể tiếp tục với các giá trị mới này. Tôi có thể vượt qua renderer các giá trị mà không có vấn đề, nhưng tôi không thể tìm ra cách để có được chúng trở lại. Tôi hiện đang sử dụng một số biến tĩnh, nhưng sau khi chúng được thay đổi bởi trình kết xuất đồ họa, chúng dường như bị mất. Họ không thể nhìn thấy trong lớp khác của tôi. Ví dụ:Vượt qua các biến giữa trình kết xuất đồ họa và lớp khác với queueEvent()

Một lớp

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

}

Trong renderer tôi:

public class MyRenderer implements GLSurfaceView.Renderer{ 

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

lớp helper của tôi:

public class Helper{ 

public static volatile boolean hasCalculated = false; 

} 

hasCalculated chắc chắn được đặt thành true trong trình kết xuất đồ họa, nhưng lớp khác của tôi luôn thấy nó là sai. Bất kỳ ý tưởng tại sao? Đoán tốt nhất của tôi là vì nó nằm trong một chủ đề khác, nhưng làm thế nào tôi có thể giải quyết được điều đó? Nếu có một cách tiếp cận sạch hơn và an toàn hơn, tôi rất vui khi được nghe anh ấy.

Trả lời

14

Bạn có thể giữ trình kết xuất của mình dưới dạng biến trong hoạt động của mình (không chỉ làm mGLView.setRenderer(new MyRenderer()); như nhiều người làm, mà là MyRenderer myRenderer = new MyRenderer(); mGLView.setRenderer(myRenderer);). Sau đó, bạn có thể giao tiếp với trình kết xuất của mình dễ dàng thông qua các cuộc gọi phương thức. Vấn đề sau đó chỉ đi xuống để giao tiếp qua chủ đề. Tôi đã đưa hai ví dụ dưới đây, một ví dụ với giao tiếp giữa một chủ đề không phải UI, chủ đề GL và luồng giao diện người dùng chính. Ví dụ thứ hai là chỉ để liên lạc giữa các chủ đề GL và thread 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 
    } 


} 


} 

Sau đó, trong renderer

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 

    } 



} 

Tôi đã sử dụng lá cờ trong ví dụ renderer trên, nhưng nó sẽ là khá đơn giản để biến mà vào một hàng đợi, nếu, nói, bạn muốn nói với trình kết xuất "nạp mảng mô hình này". Vì bạn phải tải các mô hình (hoặc ít nhất là kết cấu) trong thread GL sử dụng tay cầm GL, bạn có thể có các lớp học và chủ đề khác làm logic của bạn và vừa những thứ GL thực hiện trong thread GL



Ngoài ra, nếu bạn chỉ muốn cập nhật các thread UI sau khi tính toán của bạn được thực hiện, chứ không phải tương tác với bất kỳ chủ đề khác:

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 

    } 

} 

và sau đó từ bất cứ nơi nào:

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, cảm ơn. Tôi sẽ có một cái nhìn gần hơn vào ngày mai khi tôi trở lại làm việc. – Lennart

Các vấn đề liên quan