2011-01-18 20 views
6

Ho 30 + bitmap singoli (320x240 pixel) che vorrei per visualizzare uno dopo l'altro a schermo intero su dispositivi Android con conseguente un'animazione. Attualmente ho implementato l'animazione utilizzando un ImageView e un Timer che imposta il fotogramma successivo e quindi invia un messaggio che applicherà il fotogramma successivo. Il frame rate risultante è molto basso: < 2 fps.Disegnare res alti animazioni con frame rate elevato su Android

Il timer:

animationTimer.scheduleAtFixedRate(new TimerTask() { 
    @Override 
    public void run() { 
     Drawable frame = getNextFrame(); 
      if (frame != null) { 
       Message message = animationFrameHandler.obtainMessage(1, frame); 
       animationFrameHandler.sendMessage(message); 
      } 
     } 
    }, 0, (int) (1000.0d/fps)); 

Il gestore:

final Handler animationFrameHandler = new Handler() { 
    @Override 
    public void handleMessage(Message message) { 
     setImageDrawable((Drawable) message.obj); 
    } 
}; 

Dal momento che voglio raggiungere un frame rate fino a 30 fps devo fare uso di un altro meccanismo e sentito parlare di Canvas.drawBitmapMesh() e OpenGL.

Se possibile, vorrei evitare di utilizzare OpenGL.

Grazie per aver condiviso le tue esperienze!

risposta

5

mio approccio ora di lavoro è il seguente:

Prima di avviare l'animazione, caricare ogni fotogramma in un List<Bitmap>. Importante: Chiama il numero System.gc() se ricevi OutOfMemoryError s - questo aiuta davvero a caricare più bitmap nella memoria. Quindi ha un thread in esecuzione che registra il frame successivo su un'istanza View che quindi aggiorna il suo canvas.

Caricamento marchi e iniziare l'animazione

// Loading the frames before starting the animation 
List<Bitmap> frames = new ArrayList<Bitmap>(); 
for (int i = 0; i < 30; i++) { 
    // Load next frame (e. g. from drawable or assets folder) 
    frames.add(...); 
    // Do garbage collection every 3rd frame; really helps loading all frames into memory 
    if (i %% 3 == 0) { 
     System.gc(); 
    } 
} 

// Start animation 
frameIndex = 0; 
animationThread.start(); 

filettatura che applica il fotogramma successivo

private final class AnimationThread extends Thread { 
    @Override 
    public void run() { 
     while (!isInterrupted()) { 
      // Post next frame to be displayed 
      animationView.postFrame(frames.get(frameIndex)); 

      // Apply next frame (restart if last frame has reached) 
      frameIndex++; 
      if (frameIndex >= frames.size()) { 
       frameIndex = 0; 
      } 

      try { 
       sleep(33); // delay between frames in msec (33 msec mean 30 fps) 
      } catch (InterruptedException e) { 
       break; 
      } 
     } 
    } 
} 

L'animazione vista

class AnimationView extends View { 
    Bitmap frame = null; 

    public void postFrame(Bitmap frame) { 
     Message message = frameHandler.obtainMessage(0, frame); 
     frameHandler.sendMessage(message); 
    } 

    protected final Handler frameHandler = new Handler() { 
     @Override 
     public void handleMessage(Message message) { 
      if (message.obj != null) { 
       frame = (Bitmap) message.obj; 
      } else { 
       frame = null; 
      } 
      invalidate(); 
     } 
    } 

    @Override 
    protected void onDraw(Canvas canvas) { 
     if (frame == null) return; 
     canvas.drawARGB(0, 0, 0, 0); 
     canvas.drawBitmap(frame, null, null, null); 
    } 
} 
+0

come "avere un timer in esecuzione che registra il prossimo frame su un'istanza View", puoi dare un dettaglio in più grazie – pengwang

+1

Ciao pengwang, ho aggiornato la mia risposta per dare ulteriori approfondimenti sul mio approccio. ci sono ancora cose poco chiare –

+0

Grazie per il tuo cuore spensierato – pengwang

0

Lascerò che qualcun altro vada nel modo migliore di farlo, ma una cosa che salta immediatamente alla mente dal tuo post che non aiuta sta usando TimerTask è un modo terribile per farlo e non è pensato per l'animazione .

+0

Hai ragione! Per il mio test e come fare le animazioni è stato appena sufficiente. Come ho detto qui, FrameAnimation non è più veloce e non ti permette di dire da quale frame a loop, quindi usare TimerTask è stato semplicemente conveniente per me. –

0

Probabilmente non aiuterà con le prestazioni, ma se quei bitmap sono risorse si potrebbe desiderare di considerare l'utilizzo di un AnimationDrawable. In caso contrario, provare ad estendere Drawable e implementare l'interfaccia Animatable. Le viste hanno già il supporto integrato per l'animazione dei drawable, non c'è bisogno di usare un gestore per questo.

Un modo per migliorare le prestazioni potrebbe essere quella di abbinare la profondità di bit dei drawable a quelli della finestra corrente. Romain Guy ha fatto una nota chiave su questo e animazioni in generale una volta: http://www.youtube.com/watch?v=duefsFTJXzc

+0

Hai ragione, usare AnimationDrawable è lento come la mia implementazione. Darei un'occhiata al keynote. Grazie mille! –

2

Si dovrebbe guardare la classe FrameAnimation; http://developer.android.com/guide/topics/graphics/2d-graphics.html#frame-animation per creare animazioni di fotogrammi con animazione di Androidi.

Anche se potrebbe essere ancora troppo lento.

L'altra alternativa se non si desidera utilizzare OpenGL ES è per disegnare sulla tela come hai menzionato. Ma usa .drawBitmap, non il drawBitmapMesh. Crea un SurfaceView, che ha una discussione, che il thread dovrebbe disegnare sulla tua tela in qualsiasi intervallo tu voglia.

È piuttosto semplice, basta leggere i documenti Android, le informazioni sono tutte lì.

+0

In effetti FrameAnimation è troppo lento: mostra la stessa velocità della mia implementazione. Dato che devo seguire alcune regole particolari su come ripetere i frame, ho realizzato la mia implementazione. Vedrò la combinazione SurfaceView/.drawBitmap e fornirò un feedback qui. Grazie mille! –

+0

Grazie a C0deAttack, lo studio della pagina http://developer.android.com/guide/topics/graphics/index.html#on-surfaceview (su SurfaceView) mi ha aiutato a implementare un thread per disegnare il fotogramma successivo al fine di ottenere un'animazione usando un SurfaceView. –

+0

Sfortunatamente un SurfaceView trasparente non può essere stratificato su un altro SurfaceView che viene utilizzato per l'anteprima della fotocamera '' getHolder(). SetType (SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS '' Detto questo, ora sto usando una vista solo che viene aggiornata da un messaggio inviato da un thread che fornisce la grafica dell'animazione, ma sfortunatamente questo non fornisce le prestazioni desiderate, i frame rate> 10 fps sono difficili da ottenere con dispositivi Android a basso budget, quindi dovrò immergermi in OpenGL nei prossimi giorni. aiuto! –