1

このコードは、GameLoop という名前のクラスにあります (LunarLander サンプルに似たコード)。

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);
    }

        }

親クラスは GameView (参照 mGame) です。独自のメソッドを呼び出そうとすると
mGame.update()announce

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();
        }
    }
. . .

私はこの例外を受け取ります:

 android.view.ViewRootImpl$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views.

ここには 2 つのスレッドがあります。GameView を実行し、SurfaceView を所有するUI スレッドと、Thread の拡張であり update-draw ループのみを実行するGameLoopです。

私が理解しているように、例外は、UI スレッドのみが TextView に触れることができることを示していますtv_announcement
しかしannounce、UI スレッドで実行されていませんか? ここで何が欠けていますか?

アナウンス後の例外のログキャットは次のとおりです。

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()
4

1 に答える 1

2

ビュー階層を作成した元のスレッドのみがそのビューにアクセスできます。

おそらくワーカースレッドからではなく、UIスレッドからUIを変更しているため、エラーがスローされます。

スレッドで実行された操作からの情報、またはスレッドで実行されたプロセスからの情報で UI を更新する場合は、次のもののみを使用できます。

于 2013-03-22T09:28:36.920 に答える