2012-06-19 4 views
12

Ich arbeite an einem Live-Hintergrundbild mit einem Bildlaufhintergrund. Ich habe zwei Bitmap-Objekte, zwischen denen ich wechsle, um die zuvor gezeichneten Pixel für das nächste Bild zu behalten. Ich zeichne eine neue Zeile oben auf der Zeichenfläche und rufe drawBitmap auf, um den Rest der Pixel auf die Leinwand zu kopieren.Canvas.drawBitmap() wird zeitweise verlangsamt, was zu weißen Blitzen führt

Ich verwende ein Runnable-Objekt, um das schwere Heben durchzuführen. Es macht alle erforderlichen Kopier- und Berechnungsvorgänge und sperrt dann die Zeichenfläche, gibt einen synchronen Block auf dem Halter ein und ruft Canvas.drawBitmap (Bitmap, Rect, Rect, Paint) auf. Gelegentlich erscheint auf dem Bildschirm ein weißer Blitz, der mit hoher CPU-Aktivität zu korrelieren scheint. Bei der Verwendung von TraceView habe ich festgestellt, dass die drawBitmap-Operation, insbesondere Canvas.native_drawBitmap(), viel länger dauert als normal. In der Regel ist es in 2-4 ms abgeschlossen, aber wenn ich einen weißen Blitz sehe, kann es zwischen 10 und 100 ms dauern.

private void draw() { 
    SurfaceHolder holder = getSurfaceHolder(); 

    Canvas canvas = null; 
    prepareFrame(); 
    try { 
     canvas = holder.lockCanvas(); 
     synchronized (holder) { 
      if (canvas != null) { 
       drawFrame(canvas); 
      } 
     } 
    } catch (Exception e) { 
     e.printStackTrace(); 
    } finally { 
     if (canvas != null) 
      holder.unlockCanvasAndPost(canvas); 
    } 
    afterDrawFrame(); 
    handler.removeCallbacks(drawRunner); 
    if (visible) { 
     handler.post(drawRunner); 
    } 
} 

draw() Die Funktion wird im run() des Runnable genannt.

private void prepareFrame() { 
    num++; 
    if (num%2 == 0) { 
     mainBmp = mainBmp1; 
     mainCan.setBitmap(mainBmp1); 
     mainCan.drawBitmap(mainBmp2, source, destination, null); 
    } else { 
     mainBmp = mainBmp2; 
     mainCan.setBitmap(mainBmp2); 
     mainCan.drawBitmap(mainBmp1, source, destination, null); 
    } 
} 

Die prepareFrame() Funktion ist, wie ich festhalten den vorherigen Pixel ich gezogen habe. Das Rect, das Quelle genannt wird, ist eine Reihe kurz vor der vollen Bildschirmgröße unten, wo als Ziel eine Reihe kurz an der Spitze ist. Die drawBitmap() Anrufe in prepareFrame() sind nie länger als 2-4 ms.

private void drawFrame(Canvas can) { 
    can.drawBitmap(mainBmp, source, destination,null); 
} 

Diese einzelne Operation wird auf der Leinwand ausgeführt, während das Schloss gedrückt wird

private void afterDrawFrame() { 
    ca.calcNextRow(); 
    mainBmp.setPixels(ca.getRow(), 0, canWidth, 0, 0, canWidth, 1); 
} 

Dann wird die nächste neue Reihe von Pixeln auf eine meiner Bitmaps im Speicher gezeichnet.

Ich habe versucht, die verschiedenen Signaturen von drawBitmap() zu verwenden, aber fand sie nur im Durchschnitt langsamer und immer noch in den anomalen weißen Blitzen.

Meine Gesamtgeschwindigkeit ist großartig. Ohne die intermittierenden Blitze funktioniert es wirklich gut. Hat jemand Vorschläge, wie man die Blitze beseitigt?

Antwort

5

Es ist schwer zu wissen, was genau hier vor sich geht, weil Sie nicht die Definition oder Verwendung einiger zentraler Variablen wie "mainCan" oder "ca" einschließen. Eine vollständigere Quellenangabe wäre großartig.

Aber ...

Was ist wohl passiert, dass seit DrawFrame (Leinwand) auf Inhaber synchronisiert, aber

handler.post(drawRunner); 

ist nicht, wird es Vorkommnissen, wo Sie versuchen, mainBmp zu ziehen, um Gleichzeitig mit dem Schreiben in prepareFrame() wird der Systembereich angezeigt.

Die beste Lösung für dieses Problem wahrscheinlich eine Art doppelter Pufferung wäre, wo man so etwas wie

1) Write to a temporary bitmap 
2) Change the ref of that bitmap to the double buffer i.e. mainBmp = tempBitmap; 

Das Hauptziel zu tun ist, niemals tun schreibt lange auf die Variablen, die Sie für die System Leinwand Rendering verwenden Ändern Sie einfach die Objektreferenz.

Hoffe, das hilft.

Verwandte Themen