2015-10-02 1 views
0

Я работаю над простой игрой с графикой, используя Open GL. Я хочу, чтобы, когда происходит определенное событие, игрок получает очко, и это обновляет текстовое окно, накладывающееся на GLSurfaceView на активность игры.Android: Почему мне нужно использовать runOnUIThread() здесь?

Заранее благодарен!

Вот соответствующие части моего кода:

Деятельность:

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, что это должно быть выполнено в потоке пользовательского интерфейса, но Android Studio думает иначе. Кто-нибудь может мне это объяснить? Благодаря!

ответ

1

Изменение:

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

к:

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

Вызов dispatchMessage() вызовет сообщение, которое будет доставлено в текущем потоке

(что нить GL в вашем случае.)