使用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。任何想法为什么?我最好的猜测是,这是因为它在另一个线程中,但我将如何解决?如果有更清洁更安全的方法,我很乐意听到他的声音。
答
完成或者,如果你只是想你计算完成后更新UI线程,而不是任何其他线程交互:从任何地方
你可以在你的活动中保持你的渲染器作为一个变量(不要像许多人那样做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
}
}
});
哇,谢谢。明天当我回去工作时,我会仔细看看。 – Lennart