Android: ¿Cómo mostrar un gran gif animado dado una url?
-
03-07-2019 - |
Pregunta
Supongamos que tengo la URL para un gran gif animado y quiero hacer una actividad similar a YouTube que muestre la animación de forma continua. ¿Cómo puedo
- transmitir en la imagen?
- ¿hacer que se muestre con animación real?
Sé que ImageView
no es la respuesta, ya que solo muestra el primer fotograma.
Una ventaja sería tener acceso a su estado de almacenamiento en búfer para que yo también pueda sincronizar la transmisión de sonido, esto es parte de un YTMND aplicación de visor. Si bien podría crear un servicio que transcodifique los archivos gif públicos en un formato más agradable, me gustaría que la aplicación funcione sin dependencias adicionales.
Solución
El bosquejo general de la solución es utilizar el uso personalizado de View
que dibuja pide una Movie
para dibujar periódicamente en el Canvas
.
El primer paso es construir la instancia de Movie
. Existe una fábrica llamada decodeStream
que puede hacer que una película tenga un InputStream
pero no es suficiente usar la transmisión desde una UrlConnection
. Si intenta esto, obtendrá una IOException
cuando el cargador de películas intente llamar a reset
en la transmisión. El truco, por desafortunado que sea, es usar un BufferedInputStream
separado con una mark
configurada manualmente para decirle que guarde suficientes datos que reset
No fallará. Afortunadamente, la URLConnection
puede decirnos cuántos datos esperar. Digo que este truco es desafortunado porque efectivamente requiere que toda la imagen esté almacenada en la memoria (lo cual no es un problema para las aplicaciones de escritorio, pero es un problema grave en un dispositivo móvil con memoria limitada).
Aquí hay un fragmento del código de configuración de Movie
:
URL url = new URL(gifSource);
URLConnection conn = url.openConnection();
InputStream is = conn.getInputStream();
BufferedInputStream bis = new BufferedInputStream(is);
bis.mark(conn.getContentLength());
Movie movie = Movie.decodeStream(bis);
bis.close();
A continuación, debe crear una vista que muestre esta Película
. Una subclase de View
con un onDraw
personalizado hará el truco (suponiendo que tenga acceso a la Movie
que creó con el código anterior).
@Override protected void onDraw(Canvas canvas) {
if(movie != null) {
long now = android.os.SystemClock.uptimeMillis();
int dur = Math.max(movie.duration(), 1); // is it really animated?
int pos = (int)(now % dur);
movie.setTime(pos);
movie.draw(canvas, x, y);
}
}
La vista no se activará para volverse a dibujar sin ayuda, y llamar ciegamente a invalidate ()
al final de onDraw
es solo un desperdicio de energía. En otro hilo (probablemente el que usó para descargar los datos de la imagen), puede publicar mensajes en el hilo principal, solicitando que la vista se invalide a un ritmo constante (pero no loco).
Handler handler = new Handler();
new Thread() {
@Override public void run() {
// ... setup the movie (using the code from above)
// ... create and display the custom view, passing the movie
while(!Thread.currentThread().isInterrupted()) {
handler.post(new Runnable() {
public void run(){
view.invalidate();
}
});
try {
Thread.sleep(50); // yields 20 fps
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
}
}.start();
Una solución realmente buena tendría todo tipo de dulces barras de progreso y verificación de errores, pero el núcleo está aquí.
Otros consejos
¿Intentaste BitmapDecode
?
Hay un ejemplo en las Demos API aquí .
Glide demuestran la manera más fácil y eficiente de lograr esto con solo una línea de código: -
Glide.with(getApplicationContext())
.load(Uri.parse("https://media1.giphy.com/media/5ziaphcUWGKPu/200.gif"))
.asGif().placeholder(R.drawable.ic_launcher).crossFade()
.into(imageView);
El resultado está aquí: -
Gif tomado de aquí http://giphy.com/search/big-gif/3
Agregue jar desde aquí: - https://github.com/bumptech/glide/releases
¿Quizás AnimationDrawable podría funcionar para usted? EDITAR: no si desea cargar desde una URL como esta publicación. Lo siento
http://developer.android.com/reference/android/ graphics / drawable / AnimationDrawable.html
Dependiendo de la complejidad del GIF, es decir, si se trata de un simple indicador de carga / progreso, podría separar el GIF, guardar cada imagen por separado y usar AnimationDrawable del Marco de Android.
Para barras de progreso simples, esto puede ser menos propenso a errores, tal vez incluso más eficiente.