Ответ 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();
На самом деле хорошее решение будет иметь всевозможные слабые индикаторы прогресса и проверки ошибок, но ядро здесь.