2

我目前无法SurfaceView从不在我的主 UI 上的线程绘制到自定义。这SurfaceView会占据整个屏幕(Galaxy S3 全屏),并且必须从多个来源进行更新。

问题是自定义SurfaceView不会保存 UI 更新之间的更改。

自定义SurfaceView类在使用它的活动中定义,并且运行定期检查更新的线程(我们称之为它DrawingThread)在自定义SurfaceView类中定义。我已经完成了类似于本教程的操作。

另一个外部线程正在更新必须对 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.

据我了解的代码过程:

  • Touch 将 UI 的更改请求添加到ExternalClass.
  • DrawingThread看到列表不再为空,安全地抓取 Canvas,并postInvalidates()调用 customSurfaceViewonDraw().
  • onDraw()更新 UI 并从ExternalClass.
  • DrawingThread发布Canvas并返回等待。

我的预期行为是,我将通过连续触摸在屏幕上累积点。取而代之的是,每次触摸都会清除屏幕,给我留下背景和我最后一次触摸屏幕的一个点。

我发现这非常令人困惑,因为lockCanvas(Rect)特别提到它将通过指定“脏”部分来保存锁之间的更改。谷歌搜索让我相信大多数用户发现了相反的问题:他们想要View重绘,但每次更新都必须手动进行。

尽管我指定了一个“脏”部分来重绘,为什么程序在SurfaceView每次 UI 更新时都从头开始绘制?

毫无疑问,有人会参考我之前回答的这个问题,建议程序员使用位图。我试图避免这种情况,因为我对此很陌生,而且我不想使用大量内存(更新 UI 只是我代码的一小部分)。直接在 a 上使用简单的形状View对我来说是理想的。此外,它作为一种解决方法提供。这是 Android API 中的缺陷吗?

已经在这里和谷歌搜索了几个小时了。希望我没有错过任何明显的东西。

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 回答