2

SurfaceView現在、メイン UI にないスレッドからカスタムへの描画に問題があります。これSurfaceViewは画面全体 (フルスクリーンの Galaxy S3) を占め、複数のソースから更新する必要があります。

問題は、カスタムSurfaceViewが UI の更新の間に変更を保存しないことです。

カスタムクラスは、それを使用するアクティビティ内で定義され、更新の定期的なチェックを実行SurfaceViewするスレッド (と呼びましょう) は、カスタムクラス内で定義されます。このチュートリアルと同様にこれを行いました。DrawingThreadSurfaceView

別の外部スレッドが、UI に加える必要がある変更のリストを更新しています。DrawingThreadこのリストを 50 ミリ秒ごとにチェックし、リストが空でない場合は、再描画する必要がある長方形を計算します。

// Thread waits for change request to UI or kill order
// Build Rect at point of Touch
try {
    Canvas = _surfaceHolder.lockCanvas(Rect); 
    synchronized (_surfaceHolder) {
        postInvalidate(); //Calls custom SurfaceView's onDraw() with the correct Canvas
    }
} finally {
    if (Canvas != null) {
        _surfaceHolder.unlockCanvasAndPost(Canvas);
    }
}
// Loop

onDraw()のカスタム方法SurfaceViewは次のとおりです。

@Override
public void onDraw(Canvas canvas) {
    // Initialize vars for rectangle
    Paint.setStyle(Style.FILL);

    for (MapChanges change : ExternalClass.getMapChanges()) {
        // Build Rect at point of Touch
        // Select Color for Paint   
        canvas.drawRect(Rect, Paint);
        ExternalClass.removeMapChange(change); //Thread safe
    }
}

onDraw()これは、以前の呼び出しからの変更を忘れているという事実を除いて、問題なく機能します。現在、を使用してこれをテストしていOnTouchListenerます。

私が理解しているコード手順:

  • タッチすると、UI の変更要求が のリストに追加されますExternalClass
  • DrawingThreadリストが空でなくなったことを確認し、Canvas を安全に取得して、 customのpostInvalidates()を呼び出します。SurfaceViewonDraw()
  • onDraw()は UI を更新し、から変更要求を削除しExternalClassます。
  • DrawingThreadを投稿し、Canvas待機に戻ります。

私の予想される動作は、連続したタッチで画面にドットが蓄積されることです。代わりに、タッチするたびに画面がクリアされ、最後に画面に触れた場所の背景とちょうど 1 つのドットが残ります。

lockCanvas(Rect)「ダーティ」セクションを指定することでロック間の変更を保存すると具体的に述べているため、これは非常に紛らわしいと思います。Google で検索したところ、ほとんどのユーザーは逆の問題を見つけているように思えましたView

SurfaceView再描画する「ダーティ」セクションを指定したにもかかわらず、UI の更新ごとにプログラムが最初からきれいに描画されるのはなぜですか?

プログラマーがビットマップを使用するようにアドバイスされたこの以前に回答された質問について、誰かが私に言及することは間違いありません。これは、私がこれに慣れていないことと、大量のメモリで動作したくないという理由から、これを回避しようとしています (UI の更新はコードのごく一部です)。単純な形状を で直接操作するのViewは、私にとって理想的です。さらに、回避策として提示されます。これは Android API の欠陥ですか?

こことGoogleを数時間検索しています。露骨に明白なものを見逃していないことを願っています。

4

1 に答える 1

0

OnDraw()方程式から抜け出すことで、なんとか回避策を見つけることができました。以下の新機能DrawingPanel

class DrawingPanel extends SurfaceView implements Runnable, SurfaceHolder.Callback {

    Thread thread = null;
    SurfaceHolder surfaceHolder;
    volatile boolean running = false;

    private Paint myPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
    Random random;

    public DrawingPanel(Context context) {
        super(context);
        getHolder().addCallback(this);

        surfaceHolder = getHolder();
    }

    @Override 
    public void surfaceChanged(SurfaceHolder holder, int format, int width,
        int height) { 


    }

    @Override
    public void surfaceCreated(SurfaceHolder holder) {          
        setWillNotDraw(false); //Allows us to use invalidate() to call onDraw()

        if (!running) {
            running = true;
            thread = new Thread(this);
            thread.start();
        }
    }

    @Override
    public void surfaceDestroyed(SurfaceHolder holder) {
        try {
            running = false;    //Tells thread to stop
            thread.join();      //Removes thread from mem.
        } catch (InterruptedException e) {}
    }   

    @Override
    public void run() {
        Canvas canvas;
        Rect myRect = new Rect();
        boolean firstRun = true;

        ChangeRequest ChangeReq;

        myPaint.setStyle(Style.FILL);

        while(running) {
            try {
                Thread.sleep(50);
            } catch (Exception e) {}

            canvas = null;

            ChangeReq = getUIChangeRequests();

            if (!ChangeReq.isEmpty() || (firstRun)) {                   
                if(surfaceHolder.getSurface().isValid()) {
                    if (!firstRun) {  

                        // Calculate dirty space for editing
                        x = ChangeReq.getX();
                        y = ChangeReq.getY();

                        try {
                            myRect.set(x*RectSize, y*RectSize, x*RectSize + RectSize, y*RectSize + RectSize);
                            myPaint.setColor(Color.RED);

                            canvas = surfaceHolder.lockCanvas(myRect);

                            synchronized (surfaceHolder) {
                                // Draw
                                canvas.drawRect(myRect, myPaint);

                            }

                            // Remove ChangeRequest
                            ChangeReq.remove();

                        } finally {
                            if (canvas != null) {
                                surfaceHolder.unlockCanvasAndPost(canvas);
                            }
                        }
                    } else {
                        try {
                            // Initialize canvas as all one color
                            myRect.set(0, 0, getWidth(), getHeight());
                            myPaint.setColor(Color.DKGRAY);

                            canvas = surfaceHolder.lockCanvas();

                            synchronized (surfaceHolder) {
                                //Draw
                                canvas.drawRect(myRect, myPaint); 
                            }

                            firstRun = false;
                        } finally {
                            if (canvas != null) {
                                surfaceHolder.unlockCanvasAndPost(canvas);
                            }
                        }
                    }
                }
            }
        }
    }   
}

surfaceHolder.lockCanvas();これは私の描画の問題を解決しますが、なぜ私がを使用して初期化する必要があり、それからのみ使用して描画できるのかという興味深い質問を提起しsurfaceHolder.lockCanvas(Rect); ます。これを別の質問で尋ねます。

于 2013-03-16T21:01:25.977 に答える