5

ここで 1 回か 2 回対処された問題についてお聞きしたいのですが、数日前に直面した問題を解決するのに役立つ情報は見つかりませんでした。

キャンバスを使用して Android 用のライブ壁紙を作成したい - OpenGL を必要とするほどグラフィカルに複雑ではありません。簡単にするために、無地の背景と 2 つの小さな長方形で構成されていると仮定します。描画は 3 つの段階で構成されます (シングル スレッド)。

  1. backgroundDraw() はキャンバス全体のロックを要求し、単色で描画します
  2. draw1() は部分的な (Rect r1) ロックを要求し、ロックされた四角形にのみ描画します
  3. draw2() は部分的な (Rect r2) ロックを要求し、ロックされた四角形にのみ描画します

複数の Android バージョン (エミュレーターとデバイスの両方) でテストしました: 2.1、2.2、2.3.3。後者でのみ正常に動作しているようです (ここ: http://home.elka.pw.edu.pl/~pgawron/include/Android/android_233.jpg )。以前の Android バージョンでは、SurfaceHolder.lockCanvas(Rect dirty) resizes(!) dirty がパラメーターとしてフルスクリーンのサイズに渡され、それを使用してさらに描画すると、画面全体に描画されます (ここでは: http://home.elka.pw.edu .pl/~pgawron/include/Android/android_22.jpg )。実際、各長方形がどのように正しく描画されていないか (全画面表示) を確認できます。画面全体の色が非常に速く変化します。

残念ながら、Google は lockCanvas(Rect dirty) の適切な使用例を見つけることができませんでした。以下に、テスト目的で使用される完全で唯一のクラスを添付します。Full Eclipse プロジェクトは、提供されたスクリーンショットが配置されている場所からアクセスできます。

誰かが最終的に私を助けてコードを修正できれば、非常に感謝しています(問題が私のコードにある場合のみ)。本当に無駄な時間を過ごしました。

ブラジル、

ペトレリ

package sec.polishcode.test;

import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Rect;
import android.os.SystemClock;
import android.service.wallpaper.WallpaperService;
import android.util.Log;
import android.view.SurfaceHolder;

public class TestLiveWallpaper extends WallpaperService{

@Override
public Engine onCreateEngine() {
    return new MyEngine();
}

class MyEngine extends Engine implements SurfaceHolder.Callback {

    private final String LOGTAG = MyEngine.class.getSimpleName();
    private Paint backgroundPaint = new Paint();
    private Paint mPaint1 = new Paint();
    private Paint mPaint2 = new Paint();
    private long lastVisibilityOnChange;

    private final Rect r1 = new Rect(20, 20, 60, 280);
    private final Rect r2 = new Rect(70, 20, 110, 280);

    public MyEngine() {

        getSurfaceHolder().addCallback(this);

        backgroundPaint.setColor(Color.YELLOW);
        mPaint1.setColor(Color.LTGRAY);
        mPaint2.setColor(Color.MAGENTA);
    }

    @Override
    public void surfaceChanged(SurfaceHolder arg0, int arg1, int arg2,
            int arg3) {
        drawSurface();
    }

    @Override
    public void surfaceCreated(SurfaceHolder arg0) {
        Log.i(LOGTAG, "surfaceCreated");
    }

    @Override
    public void surfaceDestroyed(SurfaceHolder arg0) {
        Log.i(LOGTAG, "surfaceDestroyed");
    }

    @Override
    public void onCreate(SurfaceHolder surfaceHolder) {
        super.onCreate(surfaceHolder);

        setTouchEventsEnabled(true);
    }

    @Override
    public void onVisibilityChanged(boolean visible) {
        if (!visible)
            return;

        lastVisibilityOnChange = SystemClock.elapsedRealtime();
        drawSurface();
    }

    @Override
    public void onOffsetsChanged(float xOffset, float yOffset, float xStep,
            float yStep, int xPixels, int yPixels) {

        if (SystemClock.elapsedRealtime() - lastVisibilityOnChange > 30)
            return;

        Log.i(LOGTAG, "onOffsetsChanged filtered");
        drawSurface();
    }

    private void drawSurface() {
        backgroundDraw();
        draw1();
        draw2();
    }

    private void backgroundDraw() {
        final SurfaceHolder holder = getSurfaceHolder();

        Canvas c = null;
        try {
            c = holder.lockCanvas();
            if (c != null) {
                c.drawRect(holder.getSurfaceFrame(), backgroundPaint);
            }
        } finally {
            if (c != null)
                holder.unlockCanvasAndPost(c);
        }
    }

    private void draw1() {
        final SurfaceHolder holder = getSurfaceHolder();

        Canvas c = null;
        try {
            c = holder.lockCanvas(r1);
            if (c != null) {
                c.drawRect(r1, mPaint1);
            }
        } finally {
            if (c != null)
                holder.unlockCanvasAndPost(c);
        }
    }

    private void draw2() {
        final SurfaceHolder holder = getSurfaceHolder();

        Canvas c = null;
        try {
            c = holder.lockCanvas(r2);
            if (c != null) {
                c.drawRect(r2, mPaint2);
            }
        } finally {
            if (c != null)
                holder.unlockCanvasAndPost(c);
        }
    }
}
}
4

1 に答える 1

5

lockCanvas(Rect dirty) はとてもシンプルです。Android では、サーフェスはデフォルトでダブル バッファリングされることに注意してください。これは、現在のサーフェスのダーティな領域だけでなく、以前のサーフェスのダーティな領域も再ペイントして正しく機能させる必要があることを意味します。これが、lockCanvas() が渡された長方形のサイズを変更する理由です。これは、実際のダーティ領域が何であるかを示します。サーフェスが破棄されて再作成されたなどの理由で、ダーティ領域も変更される可能性があります。lockCanvas(Rect) を使用する正しい方法は、ダーティな四角形を渡してから、その新しい値を確認し、それらを尊重することです。

于 2011-08-14T03:47:22.380 に答える