从OpenGL线程使用时,Handler.dispatchMessage挂起/崩溃

时间:2012-09-10 21:53:54

标签: android opengl-es multithreading thread-synchronization

我正在开发Android的opengl游戏。当用户失去游戏时应返回主菜单,但此调用是从OpenGl ES线程到UI线程进行的,并且存在一些问题。我发现了这篇文章Pass variables between renderer and another class with queueEvent()并尝试在以下代码中添加Handler类:

public class GameActivity extends Activity {

    private GLSurfaceView gameView;
    private int menuViewID;

    private Handler gameOverHandler;

    public GameActivity () {
        super();
    }

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        gameOverHandler = new Handler() {

            public void handleMessage (Message msg){
                handleGameOver();
            }
        };
        gameView = new GameView(this, gameOverHandler);
        menuViewID = R.layout.main;

        setContentView(menuViewID);
    }

    /** Called when the user selects the Send button */
    public void startGame(View view) {
        setContentView(gameView);
        gameView.setVisibility(View.VISIBLE);
    }

    private void handleGameOver() {
        /**
         * TODO: switch back to main menu
         */

//      setContentView(menuViewID);         // after this gameView freezes
//      gameView.setVisibility(View.GONE);  // after this application throw an error: android.view.ViewRootImpl$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views.


    }
}

然后在OpenGL ES代码中

gameOverHandler.dispatchMessage(Message.obtain(gameOverHandler));

但我仍然遇到冻结或运行时异常(请参阅上面代码中的注释行)。我在这里错过了什么或做错了什么?

顺便说一句,如何获取XML中定义的View实例的引用(参见上面代码中的menuViewID),或findViewById方法返回NULL的原因?

2 个答案:

答案 0 :(得分:2)

您不想使用dispatchMessage(msg)方法。这显然与直接调用Handler相同。 (文档很差。似乎它是供系统使用的。)

在此处查看类似问题:

The difference between Handler.dispatchMessage(msg) and Handler.sendMessage(msg)

相反,你可以使用它:

gameOverHandler.obtainMessage(MY_MSG_INT_ID).sendToTarget();

答案 1 :(得分:0)

你必须在UI线程中处理它吗?我可以使用以下代码从我的游戏类中处理它:

    Intent myIntent = new Intent(myContext, EndGameActivity.class);
    ((Activity)getContext()).startActivityForResult(myIntent, 0);

我只是将UI线程活动中的上下文转换回活动,然后从那里开始我的新活动以获得结果。我发回一个结果,然后在UI线程的活动中我抓住了结果:

    @Override 
protected void onActivityResult(int requestCode, int resultCode, Intent data) { 

    super.onActivityResult(requestCode, resultCode, data); 
    if (resultCode == 1) { 
       this.finish(); 
    }

}