您好我正在使用SurfaceView绘制输入信号的实时图表。 采样率为128Hz,目标图刷新率为50Zh。
事情进展顺利,点数是实时正确绘制的。
我使用Path()在几个点的段中绘制数据 对于每个段,我调用path.computeBounds()来获取一个rect,我将用它来调用holder.lockCanvas(rect)并绘制路径。使用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;
}
}
绘制框架/清除图形代码
private void drawGraphFrame(Canvas canvas) {
if (!drawGraphFrame) {
return;
}
if (canvas == null) {
Log.e(TAG, "trying to draw on a null canvas");
return;
}
drawGraphFrame = false;
// clear the graph
canvas.drawColor(Color.BLACK, Mode.CLEAR);
// draw the graph frame
canvas.drawLine(leftMargin, topMargin, leftMargin, mCanvasHeight - bottomMargin, framePaint);
canvas.drawLine(leftMargin, mCanvasHeight - bottomMargin, mCanvasWidth - rightMargin, mCanvasHeight
- bottomMargin, framePaint);
// more drawing
}
答案 0 :(得分:0)
您的问题非常简单..您只能锁定新路径所涵盖的画布的新部分。因此,最好的办法是让你的路径和脏矩形的私人成员。然后在draw方法的开始处获取脏rect中路径的当前边界(旧边界)。现在调用path.rewind();并开始修改你的路径。在使用新边界对脏矩形进行联合之后。现在你的脏矩形覆盖旧的和新的矩形。所以你的明确将删除旧的道路。这也减少了开销,因为您不希望每秒为rect和路径分配100多个对象。现在,自绘制示波器以来,您可能希望将旧边界调整为仅视图宽度的一部分。新部分的金额相同。
希望能够解决问题。
答案 1 :(得分:0)
我的简单回答就是在你想要清除画布的地方使用这个函数clear_holder()。我复制并粘贴3行3次,因为它需要3次清除才能使支架留空。
清理持有人后,你应该画出你想要的任何新东西!
这个link给了我这个源代码!
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);
}
答案 2 :(得分:0)
看起来你正在清理画布,所以它不是双重缓冲问题。我认为它与您的路径有关,已被重复使用。
尝试在开始新页面时添加下一行。
path.reset();