本文介绍了如何使用单独的线程不失previous编辑部分重绘自定义的SurfaceView?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我目前用从一个线程,是不是我的主UI绘制一个自定义的 SurfaceView 麻烦。这 SurfaceView 占用屏幕(银河S3在全屏幕)的整体,必须从多个来源进行更新。

I am currently having trouble with drawing to a custom SurfaceView from a thread that is not on my main UI. This SurfaceView takes up the entirety of the screen (Galaxy S3 in full screen) and must be updated from several sources.

问题是,定制 SurfaceView 不会更新之间更改保存到用户界面。

The problem is that the custom SurfaceView will not save changes between updates to UI.

自定义 SurfaceView 类使用它的活动中定义的,而线程(我们称之为 DrawingThread 运行更新定期检查)的自定义 SurfaceView 类中定义。我已经这样做了类似。

The custom SurfaceView class is defined within the activity that uses it, and the thread (let's call it DrawingThread) that runs periodic checks for updates is defined within the custom SurfaceView class. I have done this similar to this tutorial.

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

Another external thread is updating a list of changes that must be made to the UI. DrawingThread checks this list every 50ms or so, and if the list is not empty, calculates a rectangle that must be redrawn.

// 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
    }
}

这完美的作品,除了一个事实,即它是忘记任何previous 的onDraw()通话变化。我目前使用这种测试的 OnTouchListener

This works flawlessly except for the fact that it is forgetting changes from any previous onDraw() call. I am currently testing this by using an OnTouchListener.

code程序我的理解是:

Code procedure as I understand it:


  • 触摸增加了对UI的改变要求在 ExternalClass 列表中。

  • DrawingThread 看到列表不再为空,安全地抓起Canvas和 postInvalidates()自定义调用的的onDraw()
  • SurfaceView
  • 的onDraw()更新UI,并移除变更请求 ExternalClass

  • DrawingThread 职位画布键,返回到等待。

  • Touch adds a change request for the UI to the list in the ExternalClass.
  • DrawingThread sees the list is no longer empty, safely grabs the Canvas, and postInvalidates() to call custom SurfaceView's onDraw().
  • onDraw() updates the UI and removes the change request from ExternalClass.
  • DrawingThread posts the Canvas and goes back to waiting.

我的预期的行为是,我会积累我的屏幕连续倒是点。相反,每个触摸清除屏幕,留下我的背景和只有一个点,我最后的触摸屏幕。

My expected behavior is that I will accumulate dots on my screen with successive touches. Instead, each touch clears the screen, leaving me with the background and exactly one dot where I last touched the screen.

我觉得这极大地混淆为 lockCanvas(矩形)特别提到,这将通过指定一个脏的部分保存锁之间的变化。谷歌搜索有使我相信,大多数用户发现相反的问题:他们想要的查看重绘,但必须这样做,每次更新手动

I find this vastly confusing as lockCanvas(Rect) specifically mentions that it will save changes between locks by designating a "dirty" section. Google searches have lead me to believe that most users find the opposite problem: that they want the View redrawn but must do so every update manually.

为什么节目,尽管我脏节的指定重绘画一个干净的 SurfaceView 从头每个UI更新?

Why is the program drawing a clean SurfaceView from scratch each UI update despite my designation of a "dirty" section to redraw?

毫无疑问,有人会引用我this previously回答那里的程序员被告知使用位图的问题。我试图避免这种情况,由于我对这个和我的愿望如何利用新的不与大量内存的工作(更新UI是我的code的一小部分)。用简单的形状直接在工作视图将是理想的我。此外,它是psented作为一种解决方法$ P $。这是Android API中的一个漏洞?

No doubt someone will reference me to this previously answered question where the programmer was advised to use bitmaps. I am trying to avoid this due to how new I am to this and my desire to not work with large amounts of memory (updating the UI is a tiny portion of my code). Working with simple shapes directly on a View would be ideal for me. Additionally it is presented as a workaround. Is this a flaw in the Android API?

现在已经在这里搜索和谷歌几个小时。希望我没有错过什么公然明显。

Have been searching here and Google for several hours now. Hope I have not missed anything blatantly obvious.

推荐答案

我设法找到通过采取的OnDraw()的方程的解决方法。新 DrawingPanel 如下:

I managed to find a workaround by taking the OnDraw() out of the equation. New DrawingPanel below:

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(矩形); 我会问这一个问题

This solves my drawing problem but brings up an interesting question of why I must initialize using surfaceHolder.lockCanvas(); and only then am able to draw using surfaceHolder.lockCanvas(Rect); I will ask this in another question.

这篇关于如何使用单独的线程不失previous编辑部分重绘自定义的SurfaceView?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

08-14 10:24