2012-06-19 13 views
12

Pracuję nad tapetą na żywo z przewijanym tłem. Mam dwa obiekty bitmapowe, które przełączam naprzemiennie, aby zachować poprzednio narysowane piksele dla następnej klatki. Narysuję nową linię u góry płótna, następnie wywołam drawBitmap, aby skopiować pozostałe piksele na płótno.Canvas.drawBitmap() jest przerywany spowolnieniem, powodując białe błyski

Używam obiektu Runnable do podnoszenia ciężkich przedmiotów. Wykonuje wszystkie wymagane kopie i obliczenia, a następnie blokuje płótno, wchodzi do bloku synchronicznego na uchwycie i wykonuje pojedyncze wywołanie Canvas.drawBitmap (bitmap, rect, rect, paint). Czasami na ekranie pojawi się biały błysk, który wydaje się korelować z wysoką aktywnością procesora. Używając funkcji traceview zauważyłem, że operacja drawBitmap, w szczególności Canvas.native_drawBitmap(), trwa znacznie dłużej niż zwykle. Zazwyczaj kończy się to w ciągu 2-4 ms, ale gdy widzę biały błysk, może to zająć od 10 do 100 ms.

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

Funkcja draw() nazywa się w run() z 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); 
    } 
} 

Funkcja prepareFrame() jest jak trzymam chwyt poprzedniego pikseli Narysowaliśmy. Rect nazywany źródłem to jeden rząd krótszy niż pełnoekranowy na dole, gdzie jako cel podróży znajduje się jeden wiersz krótszy u góry. Wywołania drawBitmap() w prepareFrame() nigdy nie są dłuższe niż 2-4 ms.

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

Ta pojedyncza operacja jest wykonywana na płótnie, przytrzymując blokadę.

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

Następnie kolejny nowy rząd pikseli jest rysowany na jednej z moich bitmap w pamięci.

Próbowałem użyć różnych sygnatur drawBitmap(), ale tylko średnio je spowolnił i nadal powoduje anomalne białe błyski.

Moja ogólna prędkość jest świetna. Bez przerywanych błysków działa naprawdę dobrze. Czy ktoś ma sugestie, jak wyeliminować błyski?

Odpowiedz

5

Trudno jest dokładnie zrozumieć, co się tutaj dzieje, ponieważ nie uwzględnia się definicji lub użycia niektórych zmiennych centralnych, takich jak "mainCan" lub "ca". Pełniejsze odniesienie do źródła byłoby świetne.

Ale ...

Co chyba że dzieje się to od drawFrame (płótno) jest zsynchronizowany na uchwycie, ale

handler.post(drawRunner); 

nie jest, nie będzie occurences gdzie próbują wyciągnąć mainBmp do płótno systemowe w tym samym czasie, w którym piszesz do niego w prepareFrame().

Najlepszym rozwiązaniem tego problemu będzie prawdopodobnie jakiś rodzaj podwójnego buforowania, gdzie można zrobić coś takiego

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

Głównym celem jest, aby nigdy nie długo pisze do zmiennych używasz do renderowania System płótnie , po prostu zmień odniesienie do obiektu.

Mam nadzieję, że to pomoże.

Powiązane problemy