Подтвердить что ты не робот

Android: Как отображать большой анимированный gif с учетом URL-адреса?

Предположим, что у меня есть URL-адрес большого анимированного gif, и я хотел сделать так, чтобы он выглядел как активность, отображающая анимацию потоковым способом. Как я

  • поток на изображении?
  • заставить его отображать текущую анимацию?

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

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

4b9b3361

Ответ 1

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

Первым шагом является создание экземпляра Movie. Существует factory, называемый 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();

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

Ответ 2

Пробовал ли вы BitmapDecode?

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

Ответ 3

Glide доказывает самый простой и эффективный способ достижения этой цели только одной строкой кода: -

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

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

введите описание изображения здесь

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

Добавьте jar отсюда: - https://github.com/bumptech/glide/releases

Ответ 4

Может быть, AnimationDrawable может работать на вас? EDIT: нет, если вы хотите загрузить с URL-адреса, как это сообщение. К сожалению

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

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

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