Андроид:Как отобразить большой анимированный GIF-файл по URL-адресу?
-
03-07-2019 - |
Вопрос
Предположим, у меня есть URL-адрес большого анимированного GIF-файла, и я хочу создать действие, подобное YouTube, которое отображает анимацию в потоковом режиме.Как мне
- поток в изображении?
- заставить его отображать настоящую анимацию?
Я знаю ImageView
это не ответ, поскольку показывает только первый кадр.
Бонусом будет доступ к состоянию его буферизации, чтобы я мог также синхронизировать потоковый звук — это часть YTMND приложение для просмотра.Хотя я мог бы создать сервис, который перекодирует общедоступные файлы gif в более удобный формат, мне бы хотелось, чтобы приложение функционировало без дополнительных зависимостей.
Решение
Общий набросок решения заключается в использовании пользовательского интерфейса. 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();
Действительно хорошее решение имело бы всевозможные индикаторы выполнения и проверку ошибок, но суть здесь.
Другие советы
Ты пробовал BitmapDecode
?
В демонстрациях API есть пример. здесь.
Скольжение доказать самый простой и эффективный способ добиться этого с помощью всего одной строки кода: -
Glide.with(getApplicationContext())
.load(Uri.parse("https://media1.giphy.com/media/5ziaphcUWGKPu/200.gif"))
.asGif().placeholder(R.drawable.ic_launcher).crossFade()
.into(imageView);
Результат здесь: -
Гифка взята отсюда http://giphy.com/search/big-gif/3
Добавьте банку отсюда: - https://github.com/bumptech/glide/releases
Может быть АнимацияDrawable может работать на тебя?РЕДАКТИРОВАТЬ:Нет, если вы хотите загружать с URL-адреса, о котором рассказывается в этом посте.Извини
http://developer.android.com/reference/android/graphics/drawable/AnimationDrawable.html
В зависимости от сложности GIF, т.е.если это простой индикатор загрузки/прогресса, вы можете разбить GIF на части, сохранить каждое изображение отдельно и использовать AnimationDrawable в Android Framework.
Для простых индикаторов выполнения это может быть менее подвержено ошибкам и, возможно, даже более производительно.