Android:为什么我必须在这里使用runOnUIThread()?

时间:2015-10-02 04:11:19

标签: android multithreading handler

我正在使用Open GL开发一款带图形的简单游戏。我想要它,以便当某个事件发生时,玩家得到一个点,这会更新覆盖游戏活动的GLSurfaceView的文本视图。

提前致谢!

以下是我的代码的相关部分:

活动:

public class playActivity extends Activity {

private GLSurfaceView myGLView;
private Handler mGameHandler;
private TextView mScoreView;

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

    mScoreView = new TextView(this);
    mScoreView.setTextColor(0xFF00FF00); // Green
    string myZeroString = "0";
    mScoreView.setText(myZeroString); //Starting score will always be 0

    mGameHandler = new Handler(){
        public void handleMessage(Message msg){
            if (msg.what == MyGLRenderer.GAME_SCORE_FLAG) {
                int score = msg.arg1;
                mScoreView.setText(Integer.toString(score));
            }

        }
    };

    myGLView = new MyGLSurfaceView(this);
    setContentView(myGLView);

    addContentView(mScoreView, new ViewGroup.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT));

}

private void updateScoreBoard(int score){
    mScoreView.setText(Integer.toString(score));
}


class MyGLSurfaceView extends GLSurfaceView{

    private final MyGLRenderer myRenderer;

    public MyGLSurfaceView(Context context){
        super(context);

        // Create an OpenGL ES 2.0 context
        setEGLContextClientVersion(2);

        myRenderer = new MyGLRenderer(context);
        myRenderer.initiateHandler(mGameHandler);

        // Set the Renderer for drawing on the GLSurfaceView
        setRenderer(myRenderer);

        setRenderMode(GLSurfaceView.RENDERMODE_CONTINUOUSLY);
    }


    }

}

GlSurfaceView.Renderer:

public class MyGLRenderer implements GLSurfaceView.Renderer{

    public static final int GAME_SCORE_FLAG = 1;
    private Handler mGameHandler = null;
    private int mScore = 0;

    public void initiateHandler(Handler handler){
        mGameHandler = handler;
    }

    ...

    @Override
    public void onDrawFrame(GL10 unused){

        if (scoreCondition){
            mScore += 1;
            if (mGameHandler != null) {
                int flag = MyGLRenderer.GAME_SCORE_FLAG;
                mGameHandler.dispatchMessage(Message.obtain(mGameHandler, flag, 2));
            }
        }


    }
}

当我运行它时,它给了我错误: " android.view.ViewRootImpl $ CalledFromWrongThreadException:只有创建视图层次结构的原始线程才能触及其视图。"

但是,在顶部的代码块中,当我替换

int score = msg.arg1;
mScoreView.setText(Integer.toString(score));

 final int score = 3;
 runOnUiThread(new Runnable() {
     @Override
     public void run() {
         mScoreView.setText(Integer.toString(score));
     }
 });

我不再收到错误而且有效。我认为在第一个构造中,当我调用setText时,它必须在UI线程上执行,但Android Studio的思维方式不同。任何人都可以向我解释这个吗?谢谢!

1 个答案:

答案 0 :(得分:1)

变化:

mGameHandler.dispatchMessage(Message.obtain(mGameHandler, flag, 2));

为:

mGameHandler.sendMessage(Message.obtain(mGameHandler, flag, 2));

调用dispatchMessage()将导致在当前线程(在您的情况下是GL线程)上传递消息。