Android: come si visualizza un grande gif animato con un url?
-
03-07-2019 - |
Domanda
Supponiamo di avere l'URL per una grande gif animata e che volessi creare un'attività simile a quella di YouTube che visualizzi l'animazione in modo streaming. Come posso
- stream nell'immagine?
- farlo visualizzare con un'animazione reale?
So che ImageView
non è la risposta in quanto mostra solo il primo fotogramma.
Un bonus avrebbe accesso al suo stato di buffering in modo da poter sincronizzare anche l'audio in streaming - questo fa parte di un YTMND applicazione visualizzatore. Mentre potrei creare un servizio che transcodifichi i file gif pubblici in un formato migliore, vorrei che l'app funzionasse senza dipendenze aggiuntive.
Soluzione
Lo schizzo generale della soluzione è utilizzare impiegare View
personalizzato che disegna chiede a un Movie
di attingere periodicamente al Canvas
.
Il primo passo è la creazione dell'istanza Movie
. Esiste una fabbrica chiamata decodeStream
che può creare un film con un InputStream
ma non è sufficiente usare lo stream da un UrlConnection
. Se provi questo, otterrai un IOException
quando il caricatore di film tenta di chiamare reset
sullo stream. L'hack, per quanto sfortunato, è usare un BufferedInputStream
separato con un mark
impostato manualmente per dirgli di salvare abbastanza dati che ripristina
non fallirà. Fortunatamente, URLConnection
può dirci quanti dati aspettarci. Dico che questo hack è sfortunato perché richiede effettivamente che l'intera immagine sia bufferizzata in memoria (il che non è un problema per le app desktop, ma è un problema serio su un dispositivo mobile con memoria limitata).
Ecco un'istantanea del codice di installazione 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();
Successivamente, è necessario creare una vista che visualizzi questo film
. Una sottoclasse di Visualizza
con un onDraw
personalizzato farà il trucco (supponendo che abbia accesso al Movie
che hai creato con il codice precedente).
@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 non si attiverà per essere ridisegnata senza aiuto e chiamare alla cieca invalidate ()
alla fine di onDraw
è solo uno spreco di energia. In un altro thread (probabilmente quello che hai usato per scaricare i dati dell'immagine), puoi pubblicare messaggi nel thread principale, chiedendo che la vista venga invalidata a un ritmo costante (ma non folle).
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 soluzione davvero piacevole avrebbe tutti i tipi di dolci barre di avanzamento e controllo degli errori, ma il nucleo è qui.
Altri suggerimenti
Hai provato BitmapDecode
?
C'è un esempio nelle demo API qui .
Glide si dimostrano il modo più semplice ed efficiente per raggiungere questo obiettivo con solo una riga di codice: -
Glide.with(getApplicationContext())
.load(Uri.parse("https://media1.giphy.com/media/5ziaphcUWGKPu/200.gif"))
.asGif().placeholder(R.drawable.ic_launcher).crossFade()
.into(imageView);
Il risultato è qui: -
GIF tratte da qui http://giphy.com/search/big-gif/3
Aggiungi jar da qui: - https://github.com/bumptech/glide/releases
Forse AnimationDrawable potrebbe funzionare per te? EDIT: Non se si desidera caricare da un URL come questo post riguarda. Siamo spiacenti
http://developer.android.com/reference/android/ grafica / drawable / AnimationDrawable.html
A seconda della complessità della GIF, ovvero se si tratta di un semplice indicatore di caricamento / avanzamento, è possibile dividere la GIF, salvare ogni immagine separatamente e utilizzare AnimationDrawable di Android Framework.
Per semplici barre di avanzamento questo potrebbe essere meno soggetto a errori, forse anche più performante.