Рисуйте анимацию в высоком разрешении с высокой частотой кадров на Android - PullRequest
6 голосов
/ 18 января 2011

У меня есть 30+ одиночных растровых изображений (320x240 пикселей), которые я хотел бы отображать одно за другим в полноэкранном режиме на устройствах Android, что приводит к анимации. В настоящее время я реализовал анимацию, используя ImageView и таймер, который устанавливает следующий кадр, а затем отправляет сообщение, которое будет применять следующий кадр. Результирующая частота кадров очень низкая: <2 кадра в секунду. </p>

Таймер:

animationTimer.scheduleAtFixedRate(new TimerTask() {
    @Override
    public void run() {
        Drawable frame = getNextFrame();
            if (frame != null) {
                Message message = animationFrameHandler.obtainMessage(1, frame);
                animationFrameHandler.sendMessage(message);
            }
        }
    }, 0, (int) (1000.0d / fps));

Обработчик:

final Handler animationFrameHandler = new Handler() {
    @Override
    public void handleMessage(Message message) {
        setImageDrawable((Drawable) message.obj);
    }
};

Поскольку я хочу достичь частоты кадров до 30 кадров в секунду, я должен использовать другой механизм и слышать о Canvas.drawBitmapMesh () и OpenGL .

Если возможно, я бы хотел не использовать OpenGL.

Спасибо, что поделились своим опытом!

Ответы [ 4 ]

5 голосов
/ 24 февраля 2011

Мой рабочий подход следующий:

Перед запуском анимации загрузите каждый кадр в List<Bitmap>.Важно: Звоните System.gc(), если вы получаете OutOfMemoryError с - это действительно помогает загружать больше растровых изображений в память.Затем запустите поток, который отправляет следующий кадр в экземпляр View, а затем обновляет его холст.

Загрузка кадров и запуск анимации

// Loading the frames before starting the animation
List<Bitmap> frames = new ArrayList<Bitmap>();
for (int i = 0; i < 30; i++) {
    // Load next frame (e. g. from drawable or assets folder)
    frames.add(...);
    // Do garbage collection every 3rd frame; really helps loading all frames into memory
    if (i %% 3 == 0) {
        System.gc();
    }
}

// Start animation
frameIndex = 0;
animationThread.start();

Тема, которая применяет следующий кадр

private final class AnimationThread extends Thread {
    @Override
    public void run() {
        while (!isInterrupted()) {
            // Post next frame to be displayed
            animationView.postFrame(frames.get(frameIndex));

            // Apply next frame (restart if last frame has reached)
            frameIndex++;
            if (frameIndex >= frames.size()) {
                frameIndex = 0;
            }

            try {
                sleep(33); // delay between frames in msec (33 msec mean 30 fps)
            } catch (InterruptedException e) {
                break;
            }
        }
    }
}

Вид анимации

class AnimationView extends View {
    Bitmap frame = null;

    public void postFrame(Bitmap frame) {
        Message message = frameHandler.obtainMessage(0, frame);
        frameHandler.sendMessage(message);
    }

    protected final Handler frameHandler = new Handler() {
        @Override
        public void handleMessage(Message message) {
            if (message.obj != null) {
                frame = (Bitmap) message.obj;
            } else {
                frame = null;
            }
            invalidate();
        }
    }

    @Override
    protected void onDraw(Canvas canvas) {
        if (frame == null) return;
        canvas.drawARGB(0, 0, 0, 0);
        canvas.drawBitmap(frame, null, null, null);
    }
}
2 голосов
/ 18 января 2011

Вы должны посмотреть на класс FrameAnimation;http://developer.android.com/guide/topics/graphics/2d-graphics.html#frame-animation для создания покадровой анимации с анимацией Android.

Хотя это все еще может быть слишком медленным.

Другой вариант, если вы не хотите использовать OpenGL ES, это рисоватьна холсте, как вы упомянули.Но просто используйте .drawBitmap, а не drawBitmapMesh.Создайте SurfaceView с потоком, который должен рисовать на вашем Canvas с любым интервалом, который вы хотите.

Это довольно просто, просто прочитайте документы по Android, вся информация есть.

0 голосов
/ 18 января 2011

Возможно, это не повлияет на производительность, но если эти растровые изображения являются ресурсами, вы можете рассмотреть возможность использования AnimationDrawable. Если нет, попробуйте расширить Drawable и реализовать интерфейс Animatable. В представлениях уже есть встроенная поддержка анимации для рисования, для этого не нужно использовать обработчик.

Одним из способов повышения производительности может быть сопоставление битовой глубины прорисовки с текущим окном. Ромэн Гай однажды выступил с основным докладом по этому поводу и анимации: http://www.youtube.com/watch?v=duefsFTJXzc

0 голосов
/ 18 января 2011

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

...