在Android上使用帧创建动画启动画面

3

这里的问题是,我在网上搜索了每一个问题和链接,但是没有一个有用的。 我有120个动画帧以.jpg格式保存,用于我的启动屏幕。我知道jpeg文件会在内存中转换成位图,所以我会遇到OutOfMemoryError。我最多只能播放10帧动画。是否有办法逐帧播放,或者我应该尝试其他方法。这是我的代码:

    final AnimationDrawable anim = new AnimationDrawable();
    anim.setOneShot(true);

    for (int i = 1; i <= 120; i++) 
    {
        Drawable logo = getResources().getDrawable(getResources()
                  .getIdentifier("l"+i, "drawable", getPackageName()));

        anim.addFrame(logo, 50);
        if (i % 3 == 0)
        {
            System.gc();
        }
    }

    ImageView myImageView = (ImageView) findViewById(R.id.SplashImageView);
    myImageView.setBackgroundDrawable(anim);
    myImageView.post(new Runnable()
    {
       public void run()
       {
          anim.start();
       }
    });

我已经将120个JPEG图片放在drawable文件夹下,并使用“l”前缀(例如l1、l2等)。 我每处理3个JPEG图片就进行一次垃圾回收,但这并没有起到任何作用。


1
你尝试在XML中使用Animation-List了吗? - Stefan de Bruijn
是的...复制粘贴了120次“几乎”相同的东西真的很痛苦。(我太愚蠢了,没有在之前试过几个JPEG文件) - Crew Peace
任何动画来说,120 帧都太多了。 - icaptan
3个回答

4
您可以尝试使用Handler.postDelayed而不是AnimationDrawable。代码示例如下:
final ImageView image = (ImageView) findViewById(R.id.SplashImageView);
final Handler handler = new Handler();

final Runnable animation = new Runnable() {
    private static final int MAX = 120;
    private static final int DELAY = 50;

    private int current = 0;

    @Override
    public void run() {
        final Resources resources = getResources();
        final int id = resources.getIdentifier("l" + current, "drawable", getPackageName());
        final Drawable drawable = resources.getDrawable(id);

        image.setBackgroundDrawable(drawable);
        handler.postDelayed(this, DELAY);
        current = (current + 1) % MAX;
    }
};

handler.post(animation);

这种解决方案需要更少的内存,因为它只在当前时间保留一个可绘制对象。

您可以使用handler.removeCallbacks(animation);取消动画。

如果您想进行一次性动画,可以有条件地调用handler.postDelayed

if (current != MAX - 1) {
    handler.postDelayed(this, DELAY);
}

那几乎就是我想要的! 非常感谢。虽然它有点卡顿,而且帧分辨率真的很差。 - Crew Peace
这段代码没有处理帧分辨率,因此您应该使用质量更好的帧。或者尝试使用setImageDrawable而不是setBackgroundDrawable - Vladimir Mironov
又是一个愚蠢的问题。我该如何让它停止?它无限运行,导致我找不到资源而出现错误(l121不存在)。 - Crew Peace
嗯...你不应该出现这个错误...不过,看看我的更新答案,也许能帮到你。 - Vladimir Mironov

1
你需要在不再使用位图时调用.recycle(),否则它们将无法被正确回收。

同时在清单文件中将 uses large heap 设置为 true。这样可以给你更多的空间,让你喘口气。>)


你能更具体一些吗?当AnimationDrawable已经“started()”后,我该如何调用recycle()函数? - Crew Peace
啊,我的错。抱歉,我需要喝杯咖啡 :) 看起来不对。你正在使用可绘制对象而不是位图。这些不需要调用回收。抱歉.. - pumpkee
嗯...正如这篇帖子所建议的那样,你可能需要使用openGL来制作启动画面:http://stackoverflow.com/questions/5136385/how-to-use-lots-of-bitmaps-in-a-game-without-exceeding-vm-memory-budget - pumpkee

1
我尝试了所有这些解决方案,每一个都有所改进 :D 我可以使用更多的帧和更高的分辨率,但仍无法满足经理们的要求 :( 我发现最好的解决方案是使用视频代替帧,即使在内存较低的设备上也能完美运行。我在只有256MB RAM的Xperia U上测试了150个大小为480*854的帧,使用了视频编解码器(H.264 mp4)。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接