2011-01-18 11 views
6

Tengo más de 30 mapas de bits individuales (320x240 píxeles) que me gustaría mostrar uno tras otro en pantalla completa en dispositivos Android, lo que da como resultado una animación. Actualmente implementé la animación usando un ImageView y un temporizador que establece el siguiente fotograma y luego envía un mensaje que aplicará el siguiente fotograma. La velocidad de cuadros resultante es muy baja: < 2 fps.Dibuja animaciones de alta resolución con alta velocidad de cuadro en Android

El temporizador:

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

El manejador:

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

Desde que quiero lograr velocidades de cuadro de hasta 30 fps tengo que hacer uso de otro mecanismo y hablar de Canvas.drawBitmapMesh() y OpenGL.

De ser posible, me gustaría evitar el uso de OpenGL.

¡Muchas gracias por compartir tus experiencias!

Respuesta

5

Mi enfoque ahora está trabajando es la siguiente:

Antes de iniciar la animación, cargue cada cuadro en una List<Bitmap>. Importante: Llame al System.gc() si obtiene OutOfMemoryError s - eso realmente ayuda a cargar más mapas de bits en la memoria. Luego, ejecute un subproceso que publique el siguiente fotograma en una instancia de Vista que luego actualice su lienzo.

Cargando los marcos e iniciar la animación

// 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(); 

rosca que se aplica el siguiente fotograma

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

La vista animación

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

cómo "tener un temporizador en ejecución que publique el siguiente fotograma a una instancia de Vista", puede dar más detalles gracias – pengwang

+1

Hola pengwang, actualicé mi respuesta para dar más información sobre mi enfoque. Siéntase libre de preguntar si todavía hay cosas poco claras. –

+0

Gracias por su corazón de guerra – pengwang

0

Voy a dejar que alguien más entre en la mejor manera de hacerlo, pero una cosa que inmediatamente me viene a la mente de su publicación que no ayuda es utilizar TimerTask es una manera terrible de hacer esto y no está destinado a la animación .

+0

¡Tienes razón! Para mi prueba y cómo hacer animaciones fue suficiente. Como mencioné aquí, FrameAnimation no es más rápido y no te permite decir de qué cuadro a bucle, así que usar TimerTask fue muy conveniente para mí. –

0

Probablemente no ayude con el rendimiento, pero si esos mapas de bits son recursos que puede considerar utilizar un AnimationDrawable. De lo contrario, intente ampliar Drawable e implemente la interfaz Animatable. Las vistas ya tienen soporte integrado para animar los objetos dibujables, sin necesidad de utilizar un controlador para eso.

Una forma de mejorar el rendimiento podría ser hacer coincidir la profundidad de bits de los dibujables con los de su ventana actual. Romain Guy hizo una presentación sobre esto y animaciones en general una vez: http://www.youtube.com/watch?v=duefsFTJXzc

+0

Tiene razón, usar AnimationDrawable es tan lento como mi implementación. Voy a echar un vistazo a la nota clave. ¡Gracias hasta ahora! –

2

Debería mirar la clase FrameAnimation; http://developer.android.com/guide/topics/graphics/2d-graphics.html#frame-animation para hacer animación de cuadros con animación de androides.

Aunque eso podría ser demasiado lento.

La otra alternativa si no desea utilizar OpenGL ES es dibujar en el lienzo como ha mencionado. Pero solo usa .drawBitmap, no drawBitmapMesh. Cree un SurfaceView, que tiene un hilo, ese hilo debe dibujar en su lienzo en el intervalo que desee.

Es bastante sencillo, solo lea los documentos de Android, la información está allí.

+0

De hecho, FrameAnimation es demasiado lento: muestra la misma velocidad que mi implementación. Como tengo que seguir algunas reglas particulares sobre cómo repetir los marcos, hice mi propia implementación. Examinaré la combinación de SurfaceView/.drawBitmap y daré comentarios aquí. ¡Gracias hasta ahora! –

+0

Gracias C0deAttack, estudiando la página http://developer.android.com/guide/topics/graphics/index.html#on-surfaceview (en un SurfaceView) me ayudó a implementar un hilo dibujando el siguiente cuadro para lograr una animación usando un SurfaceView. –

+0

Lamentablemente, un SurfaceView transparente no se puede superponer sobre otro SurfaceView que se está utilizando para la vista previa de la cámara '' getHolder(). SetType (SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS '' Dijo esto, ahora estoy usando solo una vista que está siendo actualizada por un mensaje se envía desde un hilo que entrega los gráficos de animación. Desafortunadamente, esto no da el rendimiento deseado, las velocidades de cuadro> 10 fps difícilmente se pueden lograr en dispositivos Android de bajo presupuesto. Así que tendré que sumergirme en OpenGL los próximos días. Gracias por cada ofrecimiento ayuda! –

Cuestiones relacionadas