2012-06-19 8 views
12

Sto lavorando su uno sfondo animato con uno sfondo a scorrimento. Ho due oggetti bitmap che alternano tra di loro per mantenere i pixel disegnati in precedenza per il fotogramma successivo. Disegno una nuova riga nella parte superiore della tela, quindi richiamo drawBitmap per copiare il resto dei pixel sulla tela.Canvas.drawBitmap() viene rallentato a intermittenza, provocando flash bianchi

Sto usando un oggetto Runnable per eseguire il sollevamento pesante. Richiede tutte le operazioni di copia e di calcolo necessarie, quindi blocca la tela, inserisce un blocco sincrono sul supporto e effettua una singola chiamata a Canvas.drawBitmap (bitmap, rect, rect, paint). Occasionalmente ci sarà un flash bianco sullo schermo, che sembra correlato all'elevata attività della CPU. Nell'utilizzo di traceview, ho scoperto che l'operazione drawBitmap, in particolare Canvas.native_drawBitmap(), richiede molto più tempo del normale. Normalmente si completa in 2-4 msec, ma quando vedo un flash bianco, può richiedere da 10 a 100 msec.

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 funzione draw() viene chiamato nel run() del Runnable.

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 funzione prepareFrame() è come io continuo possesso dei pixel precedenti che ho disegnato. Il Rect chiamato source è una riga a corto di schermo intero dimensionato in basso, dove come destinazione è una fila breve in alto. Le chiamate drawBitmap() in prepareFrame() non sono mai più lunghe di 2-4 msec.

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

Questa singola operazione viene eseguita sulla tela mentre si tiene il blocco.

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

Quindi la prossima nuova riga di pixel viene disegnata su una delle mie bitmap in memoria.

Ho provato a utilizzare le varie firme di drawBitmap(), ma li ho trovati solo in media più lenti e continuando a produrre i lampi bianchi anomali.

La mia velocità complessiva è ottima. Senza i flash intermittenti, funziona davvero bene. Qualcuno ha suggerimenti su come eliminare i flash?

risposta

5

È piuttosto difficile sapere esattamente cosa sta succedendo qui perché non si include la definizione o l'uso di alcune variabili centrali come "mainCan" o "ca". Un riferimento alla fonte più completo sarebbe grandioso.

Ma ...

Cosa c'è probabilmente accade è che, poiché stiratoio (tela) è sincronizzato sul supporto, ma

handler.post(drawRunner); 

non è, ci saranno avvenimenti in cui si sta tentando di attirare l'mainBmp a la tela del sistema nello stesso momento in cui la stai scrivendo in prepareFrame().

La migliore soluzione a questo problema sarebbe probabilmente una sorta di doppio buffer, in cui si fa qualcosa di simile

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

L'obiettivo principale è quello di non fare mai a lungo scrive le variabili che si sta utilizzando per il rendering tela sistema , basta cambiare il riferimento dell'oggetto.

Spero che questo aiuti.

Problemi correlati