Search code examples
androidopengl-esmultithreadingthread-synchronization

Handler.dispatchMessage hangs/crashes when used from OpenGL thread


I'm working on an opengl game for Android. When user looses the game should return to main menu, but this call is to be done from OpenGl ES thread to UI thread and there is some troubles. I've found this post Pass variables between renderer and another class with queueEvent() and tried to add Handler class in the following code:

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.


    }
}

and then later in OpenGL ES code

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

but I'm still getting a freeze or runtime exception (see commented lines in the code above). What I'm missing here or doing wrong?

By the way, how to get the reference for the View instance that was defined in XML (see menuViewID in the code above), or why the findViewById method returns NULL?


Solution

  • You don't want to use the dispatchMessage(msg) method. That is apparently the same as calling the Handler directly. (The documentation is poor. It seems it's intended for system use).

    See similar question here:

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

    Instead, you could use this:

    gameOverHandler.obtainMessage(MY_MSG_INT_ID).sendToTarget();