【问题标题】:Efficient way to load large image sequences for animation为动画加载大型图像序列的有效方法
【发布时间】:2015-11-30 11:23:23
【问题描述】:

我有 4 个图像序列(png 格式)需要用于我的动画。每个序列大约 50 帧长,每帧大约 300x300,所以我有大约 30 MB 的资源要加载。加载它们以避免内存泄漏的最有效方法是什么?我应该选择 xml 可绘制动画还是有更好的方法?

我不需要同时在屏幕上显示所有这些。一次只会显示一个动画。

【问题讨论】:

    标签: android-animation android-drawable xml-drawable


    【解决方案1】:

    也许有点晚了 :) 但我希望这可以帮助其他用户。 最后,我通过一个简单的循环来解决它,该循环加载图像,绘制并销毁它。

            int frames = 50;
    
            //LOADING-REMOVING NEEDED FRAMES
            //set animation range
            i = currentFrame % frames;
            //frame to cache
            frameList.add(BitmapsLoader(i)); //custom function to load a specified frame from res
            if (frameList.size() == 3) {
                //frame to draw
                canvas.drawBitmap(frameList.get(1), left, top, null);
                //frame to remove
                frameList.get(0).recycle();
                frameList.remove(0);
            }
    

    无论您的动画有多少帧,这都会使内存分配保持稳定。显然,它在 CPU 上的成本更高,因为我们没有预加载所有资源,而是在每一帧继续加载它们。尽管有这些事实,我的应用程序运行顺利。 在三星 Galaxy S3 和 Galaxy Tab 4 上测试。

    【讨论】:

    • 您能否详细说明您的答案。您是对 AnimationDrawable 类进行子类化还是以自己的方式实现它?这是在 OnDraw 方法中吗?我真的很想试试你的方法,请分享更多你的解决方案...
    【解决方案2】:

    非常感谢。 我面临同样的问题,在看到你的答案一段时间后,我通过覆盖 AnimationDrawable 解决了这个问题。 因此,如果问题是您无法加载数组中的所有图像,因为它太大而内存无法容纳它,然后在需要时加载图像。 我的 AnimationDrawable 是这样的:

    public abstract class MyAnimationDrawable extends AnimationDrawable {
    
        private Context context;
        private int current;
        private int reqWidth;
        private int reqHeight;
        private int totalTime;
    
        public MyAnimationDrawable(Context context, int reqWidth, int reqHeight) {
            this.context = context;
            this.current = 0;
            //In my case size of screen to scale Drawable
            this.reqWidth = reqWidth;
            this.reqHeight = reqHeight;
            this.totalTime = 0;
        }
    
        @Override
        public void addFrame(Drawable frame, int duration) {
            super.addFrame(frame, duration);
            totalTime += duration;
        }
    
        @Override
        public void start() {
            super.start();
            new Handler().postDelayed(new Runnable() {
    
                public void run() {
                    onAnimationFinish();
                }
            }, totalTime);
        }
    
        public int getTotalTime() {
            return totalTime;
        }
    
        @Override
        public void draw(Canvas canvas) {
            try {
                //Loading image from assets, you could make it from resources 
                Bitmap bmp = BitmapFactory.decodeStream(context.getAssets().open("presentation/intro_000"+(current < 10 ? "0"+current : current)+".jpg"));
                //Scaling image to fitCenter
                Matrix m = new Matrix();
                m.setRectToRect(new RectF(0, 0, bmp.getWidth(), bmp.getHeight()), new RectF(0, 0, reqWidth, reqHeight), Matrix.ScaleToFit.CENTER);
                bmp = Bitmap.createBitmap(bmp, 0, 0, bmp.getWidth(), bmp.getHeight(), m, true);
                //Calculating the start 'x' and 'y' to paint the Bitmap 
                int x = (reqWidth - bmp.getWidth()) / 2;
                int y = (reqHeight - bmp.getHeight()) / 2;
                //Painting Bitmap in canvas
                canvas.drawBitmap(bmp, x, y, null);
                //Jump to next item
                current++;
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    
        abstract void onAnimationFinish();
    
    }
    

    现在要播放动画你需要做什么

        //Get your ImageView
        View image = MainActivity.this.findViewById(R.id.presentation);
    
        //Create AnimationDrawable
        final AnimationDrawable animation = new MyAnimationDrawable(this, displayMetrics.widthPixels, displayMetrics.heightPixels) {
    
            @Override
            void onAnimationFinish() {
                //Do something when finish animation
            }
    
        };
        animation.setOneShot(true); //dont repeat animation
        //This is just to say that my AnimationDrawable has 72 frames with 50 milliseconds interval
        try {
            //Always load same bitmap, anyway you load the right one in draw() method in MyAnimationDrawable
            Bitmap bmp = BitmapFactory.decodeStream(MainActivity.this.getAssets().open("presentation/intro_00000.jpg"));
            for (int i = 0; i < 72; i++) {
                animation.addFrame(new BitmapDrawable(getResources(), bmp), 50);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    
        //Set AnimationDrawable to ImageView
        if (Build.VERSION.SDK_INT < 16) {
            image.setBackgroundDrawable(animation);
        } else {
            image.setBackground(animation);
        }
    
        //Start animation
        image.post(new Runnable() {
    
            @Override
            public void run() {
                animation.start();
            }
    
        });
    

    就是这样,对我来说工作正常!!!

    【讨论】:

      猜你喜欢
      • 2012-08-20
      • 2012-09-24
      • 1970-01-01
      • 1970-01-01
      • 2014-11-04
      • 2021-06-23
      • 1970-01-01
      • 2011-11-10
      • 2012-07-16
      相关资源
      最近更新 更多