Android: Comment afficher un grand gif animé à partir d'une URL?
-
03-07-2019 - |
Question
Supposons que j'ai l'URL d'un grand gif animé et que je souhaite créer une activité similaire à YouTube, qui affiche l'animation sous forme de diffusion en continu. Comment puis-je
- diffuser dans l'image?
- l'obtenir afficher avec l'animation réelle?
Je sais que ImageView
n’est pas la solution, il n’affiche que la première image.
Un bonus aurait accès à son statut de mise en mémoire tampon afin que je puisse également synchroniser le son en streaming - cela fait partie d'un YTMND application de visualisation. Bien que je puisse créer un service qui transcodera les fichiers gif publics dans un format plus agréable, j'aimerais que l'application fonctionne sans dépendances supplémentaires.
La solution
L'esquisse générale de la solution consiste à utiliser un View
personnalisé qui dessine demande à un Film
de se dessiner périodiquement dans le Canvas
.
La première étape consiste à créer l'instance Movie
. Il existe une usine appelée decodeStream
qui peut créer un film avec un InputStream
, mais il ne suffit pas d'utiliser le flux à partir d'un UrlConnection
. Si vous essayez ceci, vous obtiendrez une IOException
lorsque le chargeur de films essaie d'appeler reset
sur le flux. Le hack, malheureusement, consiste à utiliser un BufferedInputStream
séparé avec une marque définie manuellement
pour lui dire de sauvegarder suffisamment de données pour que reset
n'échouera pas. Heureusement, URLConnection
peut nous indiquer le volume de données à attendre. Je dis que ce hack est regrettable car il nécessite en réalité que l’ensemble de l’image soit mise en tampon dans la mémoire (ce n’est pas un problème pour les applications de bureau, mais c’est un problème grave pour un appareil mobile à mémoire limitée).
Voici un extrait du code d'installation Film
:
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();
Ensuite, vous devez créer une vue qui affichera ce Film
. Une sous-classe de View
avec un onDraw
personnalisé fera l'affaire (en supposant qu'elle ait accès au Film
que vous avez créé avec le code précédent).
@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 vue ne se déclenchera pas sans aide et l'appel aveugle de invalidate ()
à la fin de onDraw
n'est qu'un gaspillage d'énergie. Dans un autre fil (probablement celui que vous avez utilisé pour télécharger les données d'image), vous pouvez envoyer des messages au fil principal, demandant que la vue soit invalidée à un rythme soutenu (mais pas fou).
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();
Une très bonne solution aurait toutes sortes de jolies barres de progression et de vérification des erreurs, mais le coeur est ici.
Autres conseils
Avez-vous essayé BitmapDecode
?
Il existe un exemple dans les démonstrations d'API ici .
Glide est le moyen le plus simple et le plus efficace de réaliser cela simplement une ligne de code: -
Glide.with(getApplicationContext())
.load(Uri.parse("https://media1.giphy.com/media/5ziaphcUWGKPu/200.gif"))
.asGif().placeholder(R.drawable.ic_launcher).crossFade()
.into(imageView);
Le résultat est ici: -
Gif tiré d'ici http://giphy.com/search/big-gif/3
Ajoutez le fichier JAR à partir de cet emplacement: - https://github.com/bumptech/glide/releases
Peut-être que AnimationDrawable pourrait fonctionner pour vous? EDIT: Pas si vous voulez charger depuis une URL comme celle-ci. Désolé
http://developer.android.com/reference/android/ graphics / drawable / AnimationDrawable.html
En fonction de la complexité du fichier GIF, c’est-à-dire s’il s’agit d’un simple indicateur de chargement / progression, vous pouvez le séparer, enregistrer chaque image séparément et utiliser AnimationDrawable du Framework Android.
Pour les barres de progression simples, cela peut être moins sujet aux erreurs, voire plus performant.