Android 清除SurfaceView画布后如何避免重影绘制
嗨,我正在使用SurfaceView绘制输入信号的实时图形。 采样率为128Hz,目标图形刷新率为50Zh 事情进展得很顺利,点是实时绘制的 我使用Path将数据绘制为几个点的分段 对于每个段,我调用path.computeBounds以获得一个rect,我将使用它调用holder.lockCanvasrect并绘制路径。使用rect可防止闪烁并减少cpu使用 当图形到达终点时,我锁定整个画布并清除背景,绘制图形框架,然后继续绘图 问题在于,在每个新页面的开头,我都会从最后一页得到一个重影图像: 我相信这是由于打印时双缓冲/使用脏区域造成的 我一直在寻找这个问题的解决方案,但似乎没有一个适合这种类型的应用。欢迎任何帮助 谢谢 让·皮埃尔 代码如下:Android 清除SurfaceView画布后如何避免重影绘制,android,android-canvas,surfaceview,doublebuffered,Android,Android Canvas,Surfaceview,Doublebuffered,嗨,我正在使用SurfaceView绘制输入信号的实时图形。 采样率为128Hz,目标图形刷新率为50Zh 事情进展得很顺利,点是实时绘制的 我使用Path将数据绘制为几个点的分段 对于每个段,我调用path.computeBounds以获得一个rect,我将使用它调用holder.lockCanvasrect并绘制路径。使用rect可防止闪烁并减少cpu使用 当图形到达终点时,我锁定整个画布并清除背景,绘制图形框架,然后继续绘图 问题在于,在每个新页面的开头,我都会从最后一页得到一个重影图像:
private void draw() {
Point point = null;
Canvas canvas = null;
Path path = new Path();
ArrayList<Point> pointArray;
float oldX = -1;
boolean setToClear = false;
boolean isNewSegment = false;
if (samplesInQueue == 0) {
return;
}
pointArray = new ArrayList<Point>((int) samplesInQueue);
for (int i = 0; i < samplesInQueue; i++) {
// take a peek at the point without retrieving it from the point
// queue
point = Points.peek();
// check if first point of segment is the start of a page
if (i == 0) {
if (lastSegmentEndPoint != null) {
if (point.x < lastSegmentEndPoint.x) {
// yes then we will need to clear the screen now
isNewSegment = true;
}
} else {
// yes then we will need to clear the screen now
isNewSegment = true;
}
}
if (point != null) {
if (point.x > oldX) {
// put consecutive points in the path point array
point = Points.poll();
samplesInQueue--;
pointArray.add(point);
oldX = point.x;
} else {
// we have a wrap around, stop and indicate we need to clear
// the screen on the next pass
if (!isNewSegment) {
setToClear = true;
}
break;
}
}
}
// no points, return
if (pointArray.size() == 0) {
return;
}
// fill the path
for (int i = 0; i < pointArray.size(); i++) {
Point p = pointArray.get(i);
if (i == 0) {
if (lastSegmentEndPoint != null) {
if (p.x >= lastSegmentEndPoint.x) {
// if we have the end of the last segment, move to it
// and line to the new point
path.moveTo(lastSegmentEndPoint.x, lastSegmentEndPoint.y);
path.lineTo(p.x, p.y);
} else {
// otherwise just line to the new point
path.moveTo(p.x, p.y);
}
} else {
path.moveTo(p.x, p.y);
}
} else {
path.lineTo(p.x, p.y);
}
}
if (clear || isNewSegment) {
if (clear) {
clear = false;
}
// we need to clear, lock the whole canvas
canvas = holder.lockCanvas();
// draw the graph frame / scales
drawGraphFrame = true;
drawGraphFrame(canvas);
} else {
// just draw the path
RectF bounds = new RectF();
Rect dirty = new Rect();
// calculate path bounds
path.computeBounds(bounds, true);
int extra = 0;
dirty.left = (int) java.lang.Math.floor(bounds.left - extra);
dirty.top = (int) java.lang.Math.floor(bounds.top - extra);
dirty.right = (int) java.lang.Math.round(bounds.right + 0.5);
dirty.bottom = (int) java.lang.Math.round(bounds.bottom + 0.5);
// just lock what is needed to plot the path
canvas = holder.lockCanvas(dirty);
}
// draw the path
canvas.drawPath(path, linePaint);
// unlock the canvas
holder.unlockCanvasAndPost(canvas);
// remember last segment end point
lastSegmentEndPoint = pointArray.get(pointArray.size() - 1);
// set clear flag for next pass
if (setToClear) {
clear = true;
}
}
你的问题很直接。。您只能锁定新路径覆盖的画布的新部分。所以最好的办法是让你的路径和脏rect的私有成员成为你的类。然后在draw方法开始时,获取路径的当前边界,即脏rect中的旧边界。现在调用path.rewind;并开始修改您的路径。之后,使用新边界在脏矩形上进行并集。现在你的脏直肠覆盖了新旧直肠。因此,您的清除将删除旧路径。这也减少了开销,因为您不希望为rect和path每秒分配100多个对象。现在,由于您绘制的是示波器,因此您可能希望将旧边界调整为仅为视图宽度的一部分。与你的新部分所涵盖的金额相同
希望这些都能解决问题。我的简单回答是,只要你想在任何地方清理画布,就可以使用这个函数clear\u holder。我复制并粘贴了3行3次,因为它需要3次清除,以保留空白。 在结算持有人后,你应该画任何你想要的新东西! 这给我这个源代码
private void clear_holder(SurfaceHolder holder){
Canvas c = holder.lockCanvas();
c.drawColor( 0, PorterDuff.Mode.CLEAR );
holder.unlockCanvasAndPost(c);
c = holder.lockCanvas();
c.drawColor( 0, PorterDuff.Mode.CLEAR );
holder.unlockCanvasAndPost(c);
c = holder.lockCanvas();
c.drawColor( 0, PorterDuff.Mode.CLEAR );
holder.unlockCanvasAndPost(c);
}
看起来您正在清理画布,因此,这不是双缓冲问题。我认为这与你的路径被重复使用有关 尝试在开始新页面时添加下一行
path.reset();
谢谢你,西蒙。在这种情况下,这实际上不起作用。由于保留了旧点,因此回放会导致路径增长。这会导致性能在几百点后快速下降。这就是为什么我一次只画几个点。另外,在您最后的声明示波器中,我相信这就是我的代码中要完成的,rect只覆盖了所需的区域。也许我不太明白你的意思。
path.reset();