2

Androidでゲームエンジンを書こうとしていますが、スレッドにあまり詳しくありません。

私のスレッドには、描画先のサーフェスを保持する属性mSurfaceHolderがあります。私のスレッドのrun()メソッドは次のようになります。

public void run() {
    // We're running now
    setState(STATE_RUNNING);

    // Keep looping while the game is running or paused
    while (mState == STATE_RUNNING || mState == STATE_PAUSED) {
        synchronized (mSurfaceHolder) {
            // If the game is running, update physics etc.
            if (mState == STATE_RUNNING) {
                updateGame();
            }
            // Draw the game even if it's paused
            drawGame();
        }
    }
}

STATE_RUNNINGアクティビティがフォアグラウンドにあり、ゲームが実行されている必要があるときの状態を表します。 STATE_PAUSED別のアクティビティが前面に出たときの状態を表します。一時停止している間も描画する必要がある理由は完全にはわかりませんが、LunarLanderの例から収集したようです。

私が望んでいるのは、アクティビティを見ている間、ゲームが更新されて描画されることです(LogCatを使用してテストします)。そして、ホーム画面に戻るか、別のアクティビティが上に表示されると、描画されます。

アクティビティを見ている間は描画と更新が行われるので、ゲームループ自体は機能します。しかし、私が活動を離れるとき、それは効果がありません。アクティビティのonPause()から呼び出されるスレッドのpause()メソッドは次のとおりです。

public void pause() {
    Log.d("Game","Here");
    synchronized (mSurfaceHolder) {
        Log.d("Game","There");
        // If the thread is running, pause it
        if (mState == STATE_RUNNING) {
            setState(STATE_PAUSED);
        }
    }
}

ご覧のとおり、このメソッドをテストするために、いくつかのメッセージをログに記録しました。アクティビティを離れたときに見つけたのは、「ここ」はログに記録されていますが、「そこ」はログに記録されていないということです。スレッドに関する知識が限られているので(実際に何が行われるかはほとんどわかりsynchronizedません)、スレッドがサーフェスホルダーと同期できないため、これが発生すると思います。しかし、なぜ同期しないのかわかりません。アクティビティを終了してから数秒後、LogCatに次の警告が表示されます。

Activity pause timeout for HistoryRecord

なぜこれが起こるのか考えていますか?アクティビティを再開しようとしても問題はありません。スレッドはそのまま実行され続けます。

どうもありがとうございました。

編集:ちょうど何か他のものを発見しました。アクティビティを開始してから約1秒以内にアクティビティを終了すると、スレッドは正常に一時停止します。そして、同じタスクがまだ実行されている間、問題なく再開および一時停止します。なぜ短期間でうまくいくのかわかりませんが、長すぎるとうまくいきません。

編集2:わかりました...私はそれを修正しました。しかし、私は自分がやったことをやるべきではないと思います。mSurfaceHolder基本的に、pause()メソッドとsetState()メソッド(pause()で使用される)の両方から同期を削除しました。いいえ、想定どおりに機能しますが、同期が必要な理由があると思います。

おそらく私が尋ねる最良の質問はこれです:同期されたブロックを使用してスレッドをオブジェクトと同期する必要があるのはいつですか?この場合、SurfaceHolderと同期する目的は何ですか?

4

1 に答える 1

3

Javaのsynchronizeキーワードは、2つのスレッドが同時に同じオブジェクトに接触できないようにし、競合状態を防ぎます。つまり、ロックを実装します。

ほとんどの場合、ここでデッドロックが発生しています。別のスレッドがおそらくを使用しmSurfaceHolderているため、このオブジェクトのロックを保持しています。のコードはsynchronized (mSurfaceHolder)、他のスレッドが完了するまでブロックされますが、これは明らかに発生していません。

ただし、実際には変更mSurfaceHolderを加えていないため、ロックを保持する理由はありません。覚えておく必要があるのは、mStateがpause()呼び出されてから、その値を更新するまでの間にmStateが読み取られる可能性があることだけです。それが問題である場合は、で同期してmStateください。

于 2010-06-30T22:19:27.797 に答える