2012-06-19 7 views
12

Estoy trabajando en un fondo de pantalla en vivo con un fondo de desplazamiento. Tengo dos objetos de mapa de bits que alternar entre ellos para mantener los píxeles dibujados previamente para el siguiente fotograma. Dibujé una nueva línea en la parte superior del lienzo, luego llamé a drawBitmap para copiar el resto de los píxeles en el lienzo.Canvas.drawBitmap() se ralentiza intermitentemente, causando flashes blancos

Estoy usando un objeto Runnable para hacer el trabajo pesado. Realiza todas las copias y los cálculos necesarios y luego bloquea el lienzo, ingresa un bloque síncrono en el soporte y realiza una única llamada a Canvas.drawBitmap (mapa de bits, rect, rect, pintura). Ocasionalmente, aparecerá un destello blanco en la pantalla, que parece correlacionarse con una actividad alta de la CPU. Al usar traceview, descubrí que la operación drawBitmap, específicamente Canvas.native_drawBitmap(), está tardando mucho más de lo normal. Normalmente se completa en 2-4 mseg, pero cuando veo un destello blanco, puede tomar de 10 a 100 mseg.

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

La función draw() se llama en el run() del Ejecutable.

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

La función prepareFrame() es cómo mantener la suspensión de los píxeles anteriores que he dibujado. La fuente Rect called tiene una fila menos de pantalla completa en la parte inferior, donde el destino es una fila corta en la parte superior. Las llamadas drawBitmap() en prepareFrame() nunca son más largas que 2-4msec.

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

Esta operación individual se realiza en el lienzo mientras se mantiene el bloqueo.

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

Luego, la siguiente fila de píxeles se dibuja en uno de mis bitmaps en la memoria.

He intentado usar las diversas firmas de drawBitmap() pero solo las he encontrado más lentas en promedio y todavía resulta en los destellos blancos anómalos.

Mi velocidad general es excelente. Sin los flashes intermitentes, funciona realmente bien. ¿Alguien tiene sugerencias sobre cómo eliminar los flashes?

Respuesta

5

Es difícil saber exactamente qué está sucediendo aquí porque no incluye la definición o el uso de algunas variables centrales como "mainCan" o "ca". Una referencia de fuente más completa sería genial.

Pero ...

¿Qué es probable que suceda es que desde manuar (lienzo) se sincroniza en el soporte, pero

handler.post(drawRunner); 

no es así, habrá apariciones en el que se está programando para mainBmp el lienzo del sistema al mismo tiempo que lo está escribiendo en prepareFrame().

La mejor solución a este problema sería probablemente una especie de doble buffer, en el que hacer algo como

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

El objetivo principal es no hacer mucho escribe a las variables que se está utilizando para la representación de la lona del sistema , simplemente cambie la referencia del objeto.

Espero que esto ayude.

Cuestiones relacionadas