I have this code in a class named GameLoop (code similar to the LunarLander sample)
while( running ) {
Canvas canvas = null;
try {
canvas = mSurfaceHolder.lockCanvas(null);
long t = System.currentTimeMillis();
if( t - old[0] >= frame ) {
old[0] = t;
synchronized( mSurfaceHolder ) {
mGame.update();
mGame.onDraw(canvas);
}
}
}
finally {
// Do this in finally so that if an exception is thrown
// we don't leave the Surface in an inconsistent state
if( canvas != null ) mSurfaceHolder.unlockCanvasAndPost(canvas);
}
}
The parent class is GameView (reference mGame).
When mGame.update()
tries to call his own announce
method,
public class GameView extends SurfaceView implements SurfaceHolder.Callback {
. . .
private void announce(int resId) {
synchronized( mSurfaceHolder ) {
tv_announcement.setText(getContext().getString(resId));
ObjectAnimator anim = ObjectAnimator.ofFloat(tv_announcement, "alpha", 0, 1);
anim.setDuration(ANNOUNCE_DURATION).start();
}
}
. . .
I get this exception:
android.view.ViewRootImpl$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views.
There are two thread here, the UI thread, which runs GameView and owns the SurfaceView, and GameLoop which is an extension of Thread and only runs the update-draw loop.
As I understand it, the exception is telling me that only the UI thread can touch the TextView tv_announcement
.
But isn't announce
running in the UI thread? What am I missing here?
Here is the logcat of the exception after announce:
03-22 07:20:19.096: D/GameView(28250): + update(): state:IDLE, next state:CHOOSE_SIDE
03-22 07:20:19.096: D/GameView(28250): + announce(resId:2131361803)
03-22 07:20:19.096: W/dalvikvm(28250): threadid=10: thread exiting with uncaught exception (group=0xb3040180)
03-22 07:20:19.096: E/AndroidRuntime(28250): FATAL EXCEPTION: Thread-192
03-22 07:20:19.096: E/AndroidRuntime(28250): android.view.ViewRootImpl$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views.
03-22 07:20:19.096: E/AndroidRuntime(28250): at android.view.ViewRootImpl.checkThread(ViewRootImpl.java:4039)
03-22 07:20:19.096: E/AndroidRuntime(28250): at android.view.ViewRootImpl.requestLayout(ViewRootImpl.java:709)
03-22 07:20:19.096: E/AndroidRuntime(28250): at android.view.View.requestLayout(View.java:12675)
03-22 07:20:19.096: E/AndroidRuntime(28250): at android.view.View.requestLayout(View.java:12675)
03-22 07:20:19.096: E/AndroidRuntime(28250): at android.view.View.requestLayout(View.java:12675)
03-22 07:20:19.096: E/AndroidRuntime(28250): at android.view.View.requestLayout(View.java:12675)
03-22 07:20:19.096: E/AndroidRuntime(28250): at android.view.View.requestLayout(View.java:12675)
03-22 07:20:19.096: E/AndroidRuntime(28250): at android.widget.RelativeLayout.requestLayout(RelativeLayout.java:268)
03-22 07:20:19.096: E/AndroidRuntime(28250): at android.view.View.requestLayout(View.java:12675)
03-22 07:20:19.096: E/AndroidRuntime(28250): at android.widget.TextView.checkForRelayout(TextView.java:6773)
03-22 07:20:19.096: E/AndroidRuntime(28250): at android.widget.TextView.setText(TextView.java:3306)
03-22 07:20:19.096: E/AndroidRuntime(28250): at android.widget.TextView.setText(TextView.java:3162)
03-22 07:20:19.096: E/AndroidRuntime(28250): at android.widget.TextView.setText(TextView.java:3137)
03-22 07:20:19.096: E/AndroidRuntime(28250): at <package>.GameView.announce(GameView.java:436)
03-22 07:20:19.096: E/AndroidRuntime(28250): at <package>.GameView.update(GameView.java:314)
03-22 07:20:19.096: E/AndroidRuntime(28250): at <package>.GameView$GameLoop.run(GameView.java:495)
03-22 07:20:19.126: D/GameView(28250): + onWindowFocusChanged(hasWindowFocus:true)
03-22 07:20:19.126: D/GameView(28250): - onWindowFocusChanged()