0

したがって、次のようにスコアを保持するための TextView を使用したアクティビティがあります。

public class PlayGameActivity extends Activity {
    private GameThread mGameThread;
    private GameView mGameView;

    private Handler mHandler = new Handler();

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_play_game);

        final TextView scoreView = (TextView) findViewById(R.id.textView2);

        mGameView = (GameView) findViewById(R.id.gameView1);
        mGameThread = mGameView.getThread();

        mHandler.post(new Runnable() {
            @Override
            public void run() {
                if (mGameView != null) {
                    scoreView.setText(mGameThread.getScore());
                }
            }
        });
    }
}

次に、GameView で関数を次のように宣言します。

class GameView extends SurfaceView implements SurfaceHolder.Callback {
    class GameThread extends Thread {
        int score = 0;

        public String getScore(){
            return Integer.toString(score);
        }

        @Override
        public void run() {
            synchronized (mSurfaceHolder) {
                if (something){
                    score++
                }
            }
        }
    }
}

問題は、mGameThread.getScore() がスコアが更新されているのに更新されていないかのように常に 0 を返すことです。

誰かが刺激を持っているなら、それは大歓迎です。また、上記のスニペットから多くの不要なコードを取り除きました。全文を見たい場合は、次の場所で行うことができます。

4

3 に答える 3

2

Handler は 1 回だけ実行されるgetScore()ため、常に初期値が取得されます。を使用してみてくださいpostDelayed()

mHandler.postDelayed(new Runnable() {
    @Override
    public void run() {
        if (mGameView != null) {
            scoreView.setText(mGameThread.getScore());
        }
        mHandler.postDelayed(this, 1000); // run again in 1sec
    }
}, 1000);

Thomas が Handler をそのような方法で使用すべきではないと述べているように、ドキュメントからの引用は次のとおりです。

Handler には主に 2 つの用途があります。(1) 将来のある時点で実行されるメッセージとランナブルをスケジュールする。(2) 自分のスレッドとは異なるスレッドで実行されるアクションをキューに入れる。

(1)にぴったり!

于 2012-10-07T23:58:02.480 に答える
2

イベント/リスナーメカニズムを使用して、UI データを更新するためのより良い方法があります。

ループ スレッドに座っていることは、OOP スタイルのプログラミングではありません。アプリでスコアの変更が発生した場合は、間違いなく変更を検出するためのハンドルがあります。検出されたら、テキストビューへの 1 つの単純な setText 呼び出しで UI を更新します。

post(....) を呼び出して (おそらく無意識に) UI イベント キュー スタックを過密にしないでください。これにより、特にタイム ループで実行している場合に、実際のユーザー インタラクションに対する UI の応答が遅くなります。UI イベント キュー スタックはシステム全体で 1 つであることを思い出してください。これは、ユーザーのデバイスとの対話を処理するためのものです。

非 UI スレッドの使用から UI コンポーネントを変更する必要がある場合

     activity.runOnUiThread(Runnable); 

post(Runnable) の代わりにメソッド。このようにして、Runnable で定義された実行コードを少し長くすることができます (ただし、推奨されません)。それ以外の場合は、post(Runnable) のコードの実行と終了が非常に迅速であることを確認してください。

于 2012-10-08T00:45:28.137 に答える
1

他にどこから電話しますmHandler.post(Runnable)か?投稿したコードは、(onCreate から) 単一のメッセージをメイン スレッドのメッセージ キューに追加しますが、これはあまり意味がありません。このメッセージは処理され、0 が出力され、それで終わりです。したがって、これをどこかから定期的に呼び出さないと、最初の 0 の後に何も出力されません。

他の場所からも呼び出している場合Handler.post(Runnable)は、正しい場所から呼び出していることを確認してください。GameThreadUI を更新するたびに呼び出す必要があります。mHandlerそのため、 GameThread でへの参照が必要になります。たとえば、コンストラクターはGameThreadこれを行うのに適した場所です (私はGameThread内部クラスとして実装するのではなく、それぞれ独自のクラスに実装します)。GameThreadが への参照を取得したらmHandler、 を使用mHandler.post(Runnable)して UI を更新できます。例えば:

    @Override
    public void run() {
        synchronized (mSurfaceHolder) {
            if (something){
                // IMPORTANT: see "important note" at the end of this Answer                          

                mHandler.post(mRunnable); // mRunnable is preinstantiated somewhere
                score++
            }
        }
    }

重要な注意:GameThreadおそらく、リアルタイムを測定する方法を使用します (つまり、Thread.sleep(...) なしで無限ループですべてを呼び出すわけではありません)。したがって、「スコアの更新」メッセージがHandler過剰に送信されることはありません。ゲームがターン制 (リアルタイムではない) の場合、この問題はまったく発生しません。

注 2: : あなたの完全なコードを確認しましたが、あなたのゲーム ティックには FPS 規制がないようです。つまり、eg などを使用していませんThread.sleep(33)。したがって、私が上で書いたソリューションは、海賊が衝突した場合に非常に多くのメッセージを UI に送信します (そして、スコアは非常に短い時間で非常に高い値に達します -私はそれがあなたが望んでいるとは思えません)。実際、score衝突が非常に速く終了しない限り、値はおそらくすぐにオーバーフローします。したがって、すべてのゲームと同様に、コードに FPS バランスを追加することをお勧めします。

于 2012-10-07T23:59:37.077 に答える