gpt4 book ai didi

android - 如何使用单独的线程部分重绘自定义SurfaceView,而又不会丢失以前的编辑?

转载 作者:行者123 更新时间:2023-12-03 13:13:08 24 4
gpt4 key购买 nike

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

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

定制SurfaceView类是在使用该类的 Activity 中定义的,而运行定期检查更新的线程(我们将其称为DrawingThread)是在定制SurfaceView类中定义的。我完成了类似于this tutorial的操作。

另一个外部线程正在更新必须对UI进行的更改的列表。 DrawingThread每隔50ms左右检查一次此列表,如果列表不为空,则计算必须重绘的矩形。

// 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将用户界面的更改请求添加到ExternalClass中的列表中。
  • DrawingThread看到列表不再为空,安全地抓取了Canvas,并使用postInvalidates()调用自定义SurfaceViewonDraw()
  • onDraw()更新UI并从ExternalClass中删除更改请求。
  • DrawingThread发布Canvas,然后返回等待状态。

  • 我的预期行为是,我将在连续触摸时在屏幕上积聚点。取而代之的是,每次触摸都会清除屏幕,只剩下背景和我最后一次触摸屏幕时的一个点。

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

    为什么尽管我指定要重绘的“脏”部分,但该程序为什么在每个UI更新时都从头开始绘制干净的 SurfaceView

    毫无疑问,有人会将我引至 this previously answered question,建议程序员在其中使用位图。由于我对此很陌生,并且我希望不使用大量内存(更新UI只是我的代码的一小部分),因此我试图避免这种情况。对我来说,直接在 View上直接处理简单形状非常理想。此外,它是作为一种解决方法。这是Android API中的缺陷吗?

    已经在这里和Google搜索了几个小时。希望我没有错过任何显而易见的事情。

    最佳答案

    我设法通过将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);进行绘图,我将在另一个问题中提出这个问题。

    关于android - 如何使用单独的线程部分重绘自定义SurfaceView,而又不会丢失以前的编辑?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15378493/

    24 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com