【问题标题】:Android SurfaceView not retaining previously drawn objectsAndroid SurfaceView 不保留以前绘制的对象
【发布时间】:2014-05-13 03:05:03
【问题描述】:

我正在试验 SurfaceView。我的要求是首先简单地渲染一个节点(简单的可绘制)。然后,稍后再渲染更多节点

我的线程的run方法和doDraw方法的sn-ps如下。我只是想在随后的通道中渲染 2 个不同的可绘制对象,同时保留两者。问题是它会擦除第一遍中写入的任何内容(请参阅代码中的注释)。 如何保留之前绘制的对象?

    public void run() {
        Canvas canvas;
        while (_running) {
            canvas = null;
            try {
                canvas = _surfaceHolder.lockCanvas(null);
                synchronized (_surfaceHolder) {
                    doDraw(canvas, isUpdate);
                }
            } finally {
                if (canvas != null) {
                    _surfaceHolder.unlockCanvasAndPost(canvas);
                }
            }
        }
    }


    public void doDraw(Canvas canvas, boolean update){
        if(update){
            //goes here 2nd pass & wipes away things done in 1st pass
            //I want to retain whatever was drawn in 1st pass
            Bitmap thumb = BitmapFactory.decodeResource(getResources(),R.drawable.icon);
            //canvas.drawColor(Color.RED);
            canvas.drawBitmap(thumb, 0, 0, null);
        } else{
            //goes here 1st pass
            Bitmap thumb = BitmapFactory.decodeResource(getResources(), R.drawable.thumb);
            //canvas.drawColor(Color.BLACK);
            canvas.drawBitmap(thumb, 300, 300, null);
            this.isUpdate = true;
        }
    }

更新 1: 似乎仍然不起作用。我将运行代码更改为此传递一个非:

     public void run() {
        Canvas canvas;
        while (_running) {
            canvas = null;
            try {
                Rect dty = null;
                if(isUpdate == true){
//--> In 2nd pass, I was hoping that only these co-ordinates will be updated
                    dty = new Rect(0,0,100,100);  
                    canvas = _surfaceHolder.lockCanvas(dty);
                }else{
                    canvas = _surfaceHolder.lockCanvas(null);
                }
                synchronized (_surfaceHolder) {
                    doDraw(canvas, isUpdate);
                }
            } finally {
                if (canvas != null) {
                    _surfaceHolder.unlockCanvasAndPost(canvas);
                }
            }
        }
    }

后来我尝试将 0,0,1,1 传递给脏矩形。还不能让它工作...

【问题讨论】:

    标签: android android-canvas surfaceview surfaceholder


    【解决方案1】:

    SurfaceView 是双缓冲或三缓冲的。以前的内容是“保留”的,因为系统不会特意清除旧缓冲区,但您不能依赖这种行为。

    如果您指定脏矩形,框架将呈现您要求的任何内容,然后将前一个缓冲区中的非脏区域复制到新缓冲区的顶部。

    允许系统扩展脏矩形——你传递给lockCanvas()的矩形可能会被更新。您需要重新绘制其中的每个像素。

    有关此操作的(有些令人眼花缭乱的)示例,请参阅Grafika 中的“TextureView 中的简单画布”。

    有关系统工作原理的更多详细信息,请参阅this article

    【讨论】:

    • 感谢您的链接。我最终重绘了整个画布。
    • 有没有办法关闭这个缓冲而只使用单个渲染纹理?
    • @PsychoDad:您可以在屏幕外的位图或 FBO 上绘制并将其粘贴到表面。必须对表面本身进行双重缓冲以避免撕裂。
    • @fadden 我试过了,性能仍然很糟糕。我正在绘制位图的线条和路径。我尝试过调用 Invalidate(rect) 并使用 TextureView 来对位图发生更改的部分进行 blit,但速度很慢。
    • @PsychoDad:你应该打开一个新问题,详细描述你正在尝试做的事情以及到目前为止你已经尝试过的事情。
    【解决方案2】:

    我在Androiddocumentation中发现了这个有趣的注释:

    unlockCanvas() 之间永远不会保留 Surface 的内容 和 lockCanvas(),因此,Surface 区域内的每个像素 必须写。此规则的唯一例外是当脏 指定了矩形,在这种情况下,非脏像素将是 保存。

    所以要做你想做的事,看起来你需要在你的lockCanvas 调用中提供一个非空的脏矩形。此外,这仅在您的节点像素不相交时才有效。

    【讨论】:

    • 你的 if/else 之外还有原来的lockCanvas
    • 糟糕.. 复制粘贴错字。真正的代码没有那个。也更新了相关问题。
    • 嗯,我不确定您还需要什么。根据文档,您似乎做得正确。
    • 您最好只存储所有需要绘制的对象并重新绘制每个通道。
    • 是的,我最终重绘了整个画布。节点必须是有弹性的,并且尝试使用脏矩形变得有点混乱。
    猜你喜欢
    • 2023-03-24
    • 1970-01-01
    • 1970-01-01
    • 2011-12-19
    • 1970-01-01
    • 2012-06-12
    • 1970-01-01
    • 1970-01-01
    • 2012-06-25
    相关资源
    最近更新 更多