问题描述
我想从另一个类传递我的渲染器一些值.在渲染器计算完这些值之后,我在一个助手类中有一个互斥锁,它应该告诉我渲染器已经完成了计算,所以我可以继续使用这些新值.我可以毫无问题地将值传递给渲染器,但我不知道如何取回它们.我目前使用一些静态变量,但是在渲染器更改它们之后,它们似乎丢失了.他们在我的其他班级不可见.示例:
I want to pass my renderer some values from another class. After the renderer has calculated the values, I have a mutex in a helper class that should tell me that the renderer has finished calculating so I can continue with these new values. I can pass the renderer the values without problems, but I can't figure out how to get them back. I currently use some static variables, but after they are changed by the renderer, they seem to get lost. They aren't visible in my other class. Example:
一个类
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.知道为什么吗?我最好的猜测是这是因为它在另一个线程中,但我将如何解决这个问题?如果有更清洁、更安全的方法,我会很高兴听到他的意见.
hasCalculated is definitely set to true in the renderer, but my other class always sees it as false. Any idea why? My best guess is that it's because its in another thread, but how would I solve that? If there is a cleaner and safer approach, I'd be happy to hear him.
推荐答案
你可以在你的活动中保持你的渲染器作为一个变量(不要只是这样做 mGLView.setRenderer(new MyRenderer());
就像很多人一样,而是 MyRenderer myRenderer = new MyRenderer(); mGLView.setRenderer(myRenderer);
).然后,您可以通过方法调用轻松地与您的渲染器进行通信.然后问题就归结为跨线程通信.我在下面放了两个例子,一个是非 UI 线程、GL 线程和主 UI 线程之间的通信.第二个例子只是用于GL线程和UI线程之间的通信
You can keep hold of your renderer as a variable in your activity (don't just do mGLView.setRenderer(new MyRenderer());
as a lot of people do, but rather MyRenderer myRenderer = new MyRenderer(); mGLView.setRenderer(myRenderer);
). Then you can communicate with your renderer easily through method calls. The problem then just comes down to cross-thread communication. I've put two examples below, one with communication between a non-UI thread, the GL thread and the main UI thread. The second example is just for communication between the GL thread and UI thread
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 的工作
I've used flags in the renderer example above, but it would be fairly simple to turn that into a queue, if, say, you wanted to tell the renderer "load this array of models". Since you have to load the models (or at least textures) in the GL thread using the GL handle, you can have other classes and threads do your logic and have just the GL stuff done in the GL thread
<小时>
或者,如果您只想在计算完成后更新 UI 线程,而不是与任何其他线程交互:
Alternatively, if you just want to update the UI thread after your calculation is done, rather than interact with any other threads:
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
}
}
});
这篇关于使用 queueEvent() 在渲染器和另一个类之间传递变量的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持编程学习网!