Android: Как отобразить большой анимированный GIF-файл с заданным URL-адресом? - PullRequest
15 голосов
/ 01 мая 2009

Предположим, у меня есть URL-адрес для большого анимированного GIF-файла, и я хотел создать действие, похожее на YouTube, которое отображает анимацию в потоковом режиме. Как мне

  1. поток в изображении?
  2. заставить его отображаться с реальной анимацией?

Я знаю, ImageView не является ответом, поскольку показывает только первый кадр.

Бонусом будет доступ к его состоянию буферизации, поэтому я также могу синхронизировать потоковый звук - это часть приложения YTMND просмотра. Хотя я мог бы создать сервис, который перекодирует общедоступные GIF-файлы в более приятный формат, я бы хотел, чтобы приложение функционировало без дополнительных зависимостей.

Ответы [ 4 ]

12 голосов
/ 05 мая 2009

Общий эскиз решения заключается в использовании пользовательского View, который рисует, просит Movie периодически рисовать себя в Canvas.

Первый шаг - создание экземпляра Movie. Существует фабрика под названием decodeStream, которая может сделать фильм с InputStream, но недостаточно использовать поток из UrlConnection. Если вы попробуете это, вы получите IOException, когда загрузчик фильма попытается вызвать reset в потоке. Хак, как это ни прискорбно, заключается в использовании отдельного BufferedInputStream с установленным вручную mark, чтобы сказать ему, чтобы сохранить достаточно данных, чтобы reset не потерпел неудачу. К счастью, URLConnection может сказать нам, сколько данных ожидать. Я говорю, что этот взлом неудачен, потому что он эффективно требует буферизации всего изображения в памяти (что не проблема для настольных приложений, но это серьезная проблема на мобильном устройстве с ограниченным объемом памяти).

Вот фрагмент кода установки 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();

Далее вам нужно создать представление, которое будет отображать это Movie. Подкласс View с пользовательским onDraw сделает свое дело (при условии, что у него есть доступ к Movie, который вы создали с помощью предыдущего кода).

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

Представление не будет инициировать перерисовку без посторонней помощи, и слепой вызов invalidate() в конце onDraw - просто энергетическая трата. В другой ветке (вероятно, той, которую вы использовали для загрузки данных изображения) вы можете публиковать сообщения в основной ветке с просьбой сделать представление недействительным с постоянной (но не безумной) скоростью.

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

Действительно хорошее решение будет иметь все виды приятных индикаторов выполнения и проверки ошибок, но ядро ​​здесь.

1 голос
/ 02 декабря 2015

Glide - самый простой и эффективный способ достичь этого с помощью одной строки кода: -

Glide.with(getApplicationContext())
            .load(Uri.parse("https://media1.giphy.com/media/5ziaphcUWGKPu/200.gif"))
            .asGif().placeholder(R.drawable.ic_launcher).crossFade()
            .into(imageView);

Результат здесь: -

enter image description here

Gif взят отсюда http://giphy.com/search/big-gif/3

Добавить баночку отсюда: - https://github.com/bumptech/glide/releases

1 голос
/ 02 мая 2009

Вы пробовали BitmapDecode?

В демоверсиях API есть пример здесь .

0 голосов
/ 10 июля 2011

Может быть AnimationDrawable может работать на вас? РЕДАКТИРОВАТЬ: Нет, если вы хотите загрузить с URL, как этот пост о. К сожалению

http://developer.android.com/reference/android/graphics/drawable/AnimationDrawable.html

В зависимости от сложности GIF, т. Е. Если это простой индикатор загрузки / выполнения, вы можете разбить GIF на части, сохранить каждое изображение отдельно и использовать AnimationDrawable в Android Framework.

Для простых индикаторов выполнения это может быть менее подвержено ошибкам, а может быть даже более производительным.

...