2

特定の速度でビットマップをスムーズにスクロールしています。私はゲームループでこれをやっています。時折スタッター/ジャンプすることを除いて、約60 fpsで非常にスムーズにスクロールします. これらのジャンプは、1 秒に 1 回から 1 秒に数回発生します。通常、数秒の実行後に開始するか、より頻繁になりますが、これが大きな手がかりであるかどうかはわかりません.

ジャンプの理由は、実行ループの反復に通常の約 2 倍の時間がかかる場合があるためです。そのため、ビットマップはしばらく 1 つの場所にとどまり、その後さらにジャンプして追いつき、一定の速度を維持します。補間を使用して、経過時間に基づいて更新ごとにビットマップの新しい位置を割り出しました。通常よりも長い時間が経過したとき、距離全体を一度に移動するのではなく、いくつかのミニ更新を試みましたが、一時停止したビットマップはまだ非常に目立ちます.

traceview を実行したところ、余分な時間が lockCanvas 内で費やされています。ほとんどの場合、このメソッドには約 10 ミリ秒かかりますが、これらの長いケースでは約 24 ミリ秒かかります。4秒間なぞると、これが7回発生しました。

次のコードでは、実行速度が速い場合は少しスリープさせていますが、実際には違いはありません。コードのその部分を削除しても、問題は解決しません。経過時間に基づいて位置を計算しているだけなので、一定のフレーム レートである必要はありません。

@Override
    public void run() {


         long beginTime = 0;     // the time when the cycle begun
         long timeDiff;      // the time it took for the cycle to execute
         int sleepTime;      // ms to sleep (<0 if we're behind)
         sleepTime = 0;
        while (mRun) {
            Canvas c = null;

            try {
                beginTime = System.currentTimeMillis();

                c = mSurfaceHolder.lockCanvas(null);
                synchronized (mSurfaceHolder) {

                    if (mMode == STATE_RUNNING) {
                        updatePhysics();
                    }
                    doDraw(c);
                }


            } catch(Exception e){
                System.out.println(e.getStackTrace());
            }finally {

                if (c != null) {
                    mSurfaceHolder.unlockCanvasAndPost(c);
                }
            }
            timeDiff = System.currentTimeMillis() - beginTime;

            sleepTime = (int)(FRAME_PERIOD - timeDiff);

            if(sleepTime > 0){

                 try {
                    Thread.sleep(sleepTime);
                 } catch (InterruptedException e) {}
            }
        }
    }

updatePhysics() と doDraw() のコードは少し計算を行いますが、これをできるだけ効率的にしようとしました。基本的に、時間と速度に基づいてビットマップの新しい位置を計算するだけです。ビットマップが 1 つだけあり、毎回再割り当てされるわけではありません。

また、私は自分の surfaceHolder の準備ができていることを確信しているので、準備ができていない surfaceHolder への繰り返しの呼び出しが抑制されているというのは、Google を検索して見つけた一般的な答えではありません。

これを引き起こす可能性のあるアイデアはありますか?私のサーフェス ホルダーは PixelFormat.RGB_565 を使用し、私のビットマップは Bitmap.Config.RGB_565 としてエンコードされます。私はもともと、私が作成した相対レイアウトからビットマップを取得しました。

4

1 に答える 1

0

考えられる理由の 1 つは、コードが有効期間の短いオブジェクトを大量に生成し、ガベージ コレクターが定期的に起動してメモリを再利用することです。

初期のバージョンの Java では、世代別ガベージ コレクションによってこの問題がほぼ解消されるまで、これらの顕著な一時停止は開発者の悩みの種でした。ただし、私の知る限り、Android の Dalvik 仮想マシンは世代別ガベージ コレクションを採用していないため、特にループですぐに破棄するオブジェクトの作成には注意が必要です。

メモリ割り当てのプロファイルを作成すると、この問題がより明確になります。

これが実際に問題である場合は、オブジェクトを再利用するか、プリミティブを使用してデータを処理することができます。

于 2012-05-14T17:24:30.583 に答える