2014-05-14 97 views
0

您好我正在使用SurfaceView繪製輸入信號的實時圖。 採樣率爲128Hz,目標圖形刷新率爲50Zh。如何在清除SurfaceView畫布後避免鬼圖繪製

事情辦得相當順利,該點被正確繪製實時的。

我使用Path() 爲每個段調用path.computeBounds()得到一個矩形,我將用它來調用holder.lockCanvas(rect)並繪製路徑。使用矩形防止閃爍,減少CPU的使用

當圖形達到予鎖定整個畫布和清除背景,繪製圖形幀,然後繼續繪製結束

的問題是,在每一個新的「頁面」年初我從最後一頁鬼形象:

ghost image

我相信這是由雙緩衝/使用髒區造成的繪圖時。

我已經看過了這個問題,但沒有解決方案,似乎足以滿足這種類型的應用。任何幫助是最受歡迎的。

感謝 讓 - 皮埃爾·

代碼如下:

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

你的問題是相當簡單..你只鎖定新的部分新路徑覆蓋的畫布。所以最好的辦法是讓你的路和骯髒的矩形的私人成員的班級。然後,在繪圖方法開始時,在髒矩形中獲取路徑的當前邊界(舊邊界)。現在調用path.rewind();並開始修改你的路徑。在新的界限之後,在骯髒的矩形上進行聯合。現在你的骯髒rect涵蓋了舊的和新的矩形。所以你清楚會消除舊路。這也可以減少開銷,因爲您不希望每秒爲rect和路徑分配超過100個對象。現在,從繪製示波器開始,您可能希望將舊邊界調整爲視圖寬度的一部分。新部分覆蓋的金額相同。

希望這是茅塞頓開。

+0

謝謝西蒙。這在這種情況下不起作用。 rewind()會導致路徑自保留舊點以來增長。這會導致性能在幾百點之後快速下降。這就是爲什麼我一次只畫幾個點的原因。另外,在你最後的陳述(示波器)中,我相信這是我的代碼完成的結果,矩形只涵蓋了所需的區域。也許我不太明白你的意思。 –

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); 
    } 
0

看起來你正在清理畫布,所以它不是雙緩衝問題。我認爲這與你的路徑被重用有關。開始新頁面時

嘗試添加添加下一行。

path.reset();