12

背景がスクロールするライブ壁紙に取り組んでいます。次のフレームのために以前に描画されたピクセルを保持するために、2 つのビットマップ オブジェクトを交互に使用します。キャンバスの上部に新しい線を描画し、drawBitmap を呼び出して残りのピクセルをキャンバスにコピーします。

Runnable オブジェクトを使用して重い作業を行っています。必要なすべてのコピーと計算を実行してから、キャンバスをロックし、ホルダーで同期ブロックに入り、Canvas.drawBitmap(bitmap,rect,rect,paint) を 1 回呼び出します。時折、画面に白い閃光が現れることがありますが、これは CPU の使用率が高いことと関連しているようです。traceview を使用すると、drawBitmap 操作、具体的には Canvas.native_drawBitmap() に通常よりもはるかに長い時間がかかっていることがわかりました。通常は 2 ~ 4 ミリ秒で完了しますが、白い閃光が見えると、10 ~ 100 ミリ秒かかることがあります。

private void draw() {
    SurfaceHolder holder = getSurfaceHolder();

    Canvas canvas = null;
    prepareFrame();
    try {
        canvas = holder.lockCanvas();
        synchronized (holder) {
            if (canvas != null) {
                drawFrame(canvas);
            }
        }
    } catch (Exception e) {
        e.printStackTrace();
    } finally {
        if (canvas != null)
            holder.unlockCanvasAndPost(canvas);
    }
    afterDrawFrame();
    handler.removeCallbacks(drawRunner);
    if (visible) {
        handler.post(drawRunner);
    }
}

draw()関数はrun()Runnableので呼び出されます。

private void prepareFrame() {
    num++;
    if (num%2 == 0) {
        mainBmp = mainBmp1;
        mainCan.setBitmap(mainBmp1);
        mainCan.drawBitmap(mainBmp2, source, destination, null);
    } else {
        mainBmp = mainBmp2;
        mainCan.setBitmap(mainBmp2);
        mainCan.drawBitmap(mainBmp1, source, destination, null);
    }
}

関数は、prepareFrame()以前に描画したピクセルを保持する方法です。source と呼ばれる Rect は、下部が全画面サイズより 1 行不足しており、宛先が上部で 1 行不足しています。のdrawBitmap()呼び出しはprepareFrame()2 ~ 4 ミリ秒よりも長くはありません。

private void drawFrame(Canvas can) {
    can.drawBitmap(mainBmp, source, destination,null);
}

この単一の操作は、ロックを保持しながらキャンバス上で行われます。

private void afterDrawFrame() {
    ca.calcNextRow();
    mainBmp.setPixels(ca.getRow(), 0, canWidth, 0, 0, canWidth, 1);
}

次に、ピクセルの次の新しい行が、メモリ内のビットマップの 1 つに描画されます。

のさまざまなシグネチャを使用してdrawBitmap()みましたが、平均して遅く、異常な白いフラッシュが発生するだけでした。

私の全体的な速度は素晴らしいです。断続的なフラッシュがなければ、非常にうまく機能します。フラッシュをなくす方法について誰か提案がありますか?

4

1 に答える 1

5

「mainCan」や「ca」などのいくつかの中心的な変数の定義または使用が含まれていないため、ここで何が起こっているのかを正確に知るのはちょっと難しいです。より完全なソース参照は素晴らしいでしょう。

しかし...

おそらく起こっているのは、 drawFrame(canvas) がホルダーで同期されているためですが、

handler.post(drawRunner);

そうではなく、prepareFrame() でシステム キャンバスに書き込んでいるのと同時に、mainBmp をシステム キャンバスに描画しようとする場合があります。

この問題の最善の解決策は、おそらくある種のダブルバッファリングであり、次のようなことを行います

1) Write to a temporary bitmap
2) Change the ref of that bitmap to the double buffer i.e. mainBmp = tempBitmap;

主な目的は、システム キャンバスのレンダリングに使用している変数に長い書き込みを行わず、オブジェクト参照を変更することです。

お役に立てれば。

于 2012-09-25T09:18:17.823 に答える