在Android上以高帧速率绘制高分辨率动画

在Android上以高帧速率绘制高分辨率动画,android,animation,opengl-es,canvas,Android,Animation,Opengl Es,Canvas,我有30多个单位图(320x240像素),我想在Android设备上一个接一个地全屏显示,生成动画。目前,我使用一个ImageView和一个定时器来实现动画,该定时器设置下一帧,然后发送一条将应用下一帧的消息。生成的帧速率非常低:。如果没有,请尝试扩展Drawable并实现Animatable界面。视图已经内置了动画绘制支持,无需使用处理程序 提高性能的一种方法可能是将可绘制内容的位深度与当前窗口的位深度相匹配。Romain Guy曾就此和一般动画做过一次主题演讲:你应该看看FrameAnima

我有30多个单位图(320x240像素),我想在Android设备上一个接一个地全屏显示,生成动画。目前,我使用一个ImageView和一个定时器来实现动画,该定时器设置下一帧,然后发送一条将应用下一帧的消息。生成的帧速率非常低:<2 fps

计时器:

处理程序:

由于我想实现高达30 fps的帧速率,我不得不使用另一种机制,并且听说了Canvas.drawBitmapMesh()OpenGL

如果可能的话,我希望避免使用OpenGL


非常感谢您分享您的经验

我会让其他人去做这件事的最佳方式,但有一件事从你的帖子中立即跳到脑海中,那就是使用TimerTask是一种可怕的方式,它不适合用于动画。

可能对性能没有帮助,但是,如果这些位图是资源,你可能需要考虑使用<代码>动画可绘制的< /代码>。如果没有,请尝试扩展
Drawable
并实现
Animatable
界面。视图已经内置了动画绘制支持,无需使用处理程序


提高性能的一种方法可能是将可绘制内容的位深度与当前窗口的位深度相匹配。Romain Guy曾就此和一般动画做过一次主题演讲:

你应该看看FrameAnimation类;使用Androids动画执行帧动画

尽管这可能还是太慢了

如果您不想使用OpenGL ES,另一种选择是如您所述绘制画布。但是只要使用.drawBitmap,而不是drawBitmapMesh。创建一个SurfaceView,它有一个线程,该线程应该以您想要的任何间隔在画布上绘制


这很简单,只要阅读Android文档,信息都在那里。

我现在的工作方法如下:

在开始动画之前,将每个帧加载到
列表中。重要提示:如果要从内存错误中获取
OutOfMemoryError
s,请调用
System.gc()。然后运行一个线程,将下一帧发布到视图实例,然后更新其画布

加载帧并启动动画

// 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();
动画视图

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

的确,帧动画太慢了——它显示的速度与我的实现相同。因为我必须遵循一些特定的规则来重复帧,所以我自己做了实现。我将研究SurfaceView/.drawBitmap组合,并在这里给出反馈。谢谢大家!感谢C0deAttack,研究页面(在SurfaceView上)帮助我实现了一个线程绘制下一帧,以便使用SurfaceView实现动画。不幸的是,透明的SurfaceView不能层叠在另一个用于相机预览“”getHolder()。setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS“”说,我现在只使用一个视图,该视图通过发送动画图形的线程发送的消息进行更新。不幸的是,这并不能提供理想的性能,帧速率>10 fps在低预算安卓设备上很难实现。因此我将不得不深入到OpenGL中xt天。感谢所有提供的帮助!你说得对!对于我的测试,如何制作动画就足够了。正如我在这里提到的,FrameAnimation并不快,也不允许你说从哪一帧到循环,所以使用TimerTask对我来说很方便。你说得对,使用AnimationDrawable和我的实现一样慢。我会上厕所的k转到主题。谢谢大家!如何“运行计时器将下一帧发布到视图实例”,你能提供更多的细节吗?谢谢你你好,彭旺,我更新了我的答案,对我的方法有了更多的了解。请随时询问是否还有不清楚的地方。谢谢你的热情,Hi Lars Blumberg。这让我记忆犹新。我如何将位图添加到列表中,如下所示。int[]splashdrawables={R.drawable.splashframe1,R.drawable.splashframe2….};drawable drawable=getResources().getDrawable(splashdrawables[i]);frames.add(Bitmap.createBitmap(drawable.getIntrinsicWidth(),drawable.getIntrinsicHeight(),Config.ARGB_8888));亲爱的Sandy,请为此创建一个新的StackOverflow问题。这样更多的人可以分析您的问题。发布代码时,请随时链接到我的答案。
// 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);
    }
}