Android: Como uma exibição é um grande GIF animado com um URL?
-
03-07-2019 - |
Pergunta
Suponha que eu tenha o URL para um GIF animado grande e queria fazer uma atividade como o YouTube que exibe a animação de uma maneira de streaming. Como é que eu
- fluxo na imagem?
- Consegui -lo exibir com animação real?
Eu sei ImageView
não é a resposta, pois mostra apenas o primeiro quadro.
Um bônus seria ter acesso ao seu status de buffer para que eu possa sincronizar o som de streaming também - isso faz parte de um Ytmnd Aplicação do visualizador. Embora eu possa criar um serviço que transcoda os arquivos públicos GIF em um formato melhor, gostaria que o aplicativo funcionasse sem dependências adicionais.
Solução
O esboço geral da solução é usar empregar costume View
que desenha pergunta um Movie
para se desenhar para o Canvas
periodicamente.
O primeiro passo é construir o Movie
instância. Há fábrica chamada decodeStream
que pode fazer um filme dado um InputStream
Mas não é suficiente usar o fluxo de um UrlConnection
. Se você tentar isso, você receberá um IOException
Quando o carregador do filme tenta ligar reset
no fluxo. O hack, por mais infeliz, é usar um separado BufferedInputStream
com um conjunto manual mark
para dizer para salvar dados suficientes que reset
não falhará. Felizmente, o URLConnection
pode nos dizer quantos dados esperam. Eu digo que esse hack é lamentável, porque exige efetivamente que toda a imagem seja buffer na memória (o que não é problema para aplicativos de desktop, mas é um problema sério em um dispositivo móvel com restrição de memória).
Aqui está um recorte do Movie
Código de configuração:
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();
Em seguida, você precisa criar uma visão que exibirá isso Movie
. Uma subclasse de View
com um costume onDraw
fará o truque (supondo que tenha acesso ao Movie
você criou com o 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);
}
}
A visão não se aciona para ser redesenhada sem ajuda, e chamando cegamente invalidate()
no fim de onDraw
é apenas um desperdício de energia. Em outro thread (provavelmente aquele que você usou para baixar os dados da imagem), você pode postar mensagens no thread principal, pedindo que a visualização seja invalidada em um ritmo constante (mas não insano).
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();
Uma solução muito boa teria todo tipo de doces barras de progresso e verificação de erros, mas o núcleo está aqui.
Outras dicas
Você tentou BitmapDecode
?
Há um exemplo nas demos da API aqui.
Deslizar prove uma maneira mais fácil e eficiente de conseguir isso com apenas uma linha 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);
O resultado está aqui:-
GIF tirado daqui http://giphy.com/search/big-gif/3
Adicionar jar daqui:- https://github.com/bumptech/glide/releases
Pode ser Animação drawable poderia funcionar para você? EDIT: Não se você deseja carregar de um URL como esta postagem. Desculpe
http://developer.android.com/reference/android/graphics/drawable/animationdrawable.html
Dependendo da complexidade do GIF, isto é, se for um indicador simples de carregamento/progresso, você poderá separar o GIF, salve cada imagem separadamente e usar o Animation Drawable da estrutura do Android.
Para barras de progresso simples, isso pode ser menos propenso a erros, talvez ainda mais com desempenho.