Android 显示逐帧动画的最有效方法

Android 显示逐帧动画的最有效方法,android,android-animation,Android,Android Animation,我试图通过在imageview中更改图像来显示逐帧动画。我尝试用xml绘制动画,并在处理程序中更改imageview的位图。我还尝试在一个arraylist中只存储三个位图(以避免内存不足),作为一种缓存机制,但改进很低。我需要迭代36个完整的动画图像。我面临的问题是,在我使用的所有方法中,我无法在给定的50毫秒时间内完成动画。图像范围从最小的250 kb到最大的540 kb。动画的fps非常低。由于ios版本的应用程序已准备就绪,我必须显示与ios版本一致的动画。我是renderscript和

我试图通过在imageview中更改图像来显示逐帧动画。我尝试用xml绘制动画,并在处理程序中更改imageview的位图。我还尝试在一个arraylist中只存储三个位图(以避免内存不足),作为一种缓存机制,但改进很低。我需要迭代36个完整的动画图像。我面临的问题是,在我使用的所有方法中,我无法在给定的50毫秒时间内完成动画。图像范围从最小的250 kb到最大的540 kb。动画的fps非常低。由于ios版本的应用程序已准备就绪,我必须显示与ios版本一致的动画。我是renderscript和opengl的noob。是否有任何方法可以在50-60毫秒内为大图像显示平滑动画。如有任何提示或建议,我们将不胜感激。下面是动画的快照: 以下是我为任何感兴趣的人准备的图片。

尝试使用
AnimationDrawable
为您的
ImageView
。查看我的答案,例如。

在android中显示fram逐帧动画的最有效方法是使用with。

使用编程创建一个图像视图,然后将其旋转一个角度,然后制作另一个角度,然后旋转它。。对要显示的imageView的数量执行此操作。您只需为其添加一个图像。 您可以像这样旋转图像

Matrix matrix=new Matrix();
imageView.setScaleType(ScaleType.MATRIX);   //required
matrix.postRotate((float) angle, pivX, pivY);
imageView.setImageMatrix(matrix);

也许是愚蠢的回答,但它可能会帮助你。使用其他工具制作动画,并将其保存为高质量视频,然后播放视频。

是否尝试将图像导出为GIF?Android确实支持解码GIF文件


看看:

我写了一个简单的活动,做了最基本的事情:

加载线程中的所有位图,然后每40毫秒向ImageView发布一次更改

package mk.testanimation;

import android.app.Activity;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Bundle;
import android.os.Handler;
import android.util.Log;
import android.widget.ImageView;
import java.util.ArrayList;

public class MainActivity extends Activity {
    ImageView mImageView;

    private int mImageRes[] = new int[]{
        R.drawable.s0,
        R.drawable.s1,
        R.drawable.s2,
        R.drawable.s3,
        R.drawable.s4,
        R.drawable.s5,
        R.drawable.s6,
        R.drawable.s7,
        R.drawable.s8,
        R.drawable.s9,
        R.drawable.s10,
        R.drawable.s11,
        R.drawable.s12,
        R.drawable.s13,
        R.drawable.s14,
        R.drawable.s15,
        R.drawable.s16,
        R.drawable.s17,
        R.drawable.s18,
        R.drawable.s19,
        R.drawable.s20,
        R.drawable.s21,
        R.drawable.s22,
        R.drawable.s23,
        R.drawable.s24,
        R.drawable.s25,
        R.drawable.s26,
        R.drawable.s27,
        R.drawable.s28,
        R.drawable.s29,
        R.drawable.s30,
        R.drawable.s31,
        R.drawable.s32,
        R.drawable.s33,
        R.drawable.s34,
        R.drawable.s35,
    };

    private ArrayList<Bitmap> mBitmaps = new ArrayList<Bitmap>(mImageRes.length);

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        final Handler handler = new Handler();
        mImageView = new ImageView(this);
        setContentView(mImageView);
        Thread important = new Thread() {
            @Override
            public void run() {
                long timestamp = System.currentTimeMillis();
                for (int i = 0; i < mImageRes.length; i++) {
                    mBitmaps.add(BitmapFactory.decodeResource(getResources(), mImageRes[i]));
                }
                Log.d("ANIM-TAG", "Loading all bitmaps took " + (System.currentTimeMillis() - timestamp) + "ms");
                for (int i = 0; i < mBitmaps.size(); i++) {
                    final int idx = i;
                    handler.postDelayed(new Runnable() {
                        @Override
                        public void run() {
                            mImageView.setImageBitmap(mBitmaps.get(idx));
                        }
                    }, i * 40);
                }
            }
        };
        important.setPriority(Thread.MAX_PRIORITY);
        important.start();
    }
}
包mk.testanimation;
导入android.app.Activity;
导入android.graphics.Bitmap;
导入android.graphics.BitmapFactory;
导入android.os.Bundle;
导入android.os.Handler;
导入android.util.Log;
导入android.widget.ImageView;
导入java.util.ArrayList;
公共类MainActivity扩展了活动{
图像视图;
私有整数图像[]=新整数[]{
R.drawable.s0,
R.drawable.s1,
R.drawable.s2,
R.drawable.s3,
R.drawable.s4,
R.drawable.s5,
R.drawable.s6,
R.drawable.s7,
R.drawable.s8,
R.drawable.s9,
R.drawable.s10,
R.drawable.s11,
R.drawable.s12,
R.drawable.s13,
R.D.s14,
R.drawable.s15,
R.drawable.s16,
R.drawable.s17,
R.drawable.s18,
R.drawable.s19,
R.drawable.s20,
R.drawable.s21,
R.drawable.s22,
R.drawable.s23,
R.drawable.s24,
R.drawable.s25,
R.drawable.s26,
R.drawable.s27,
R.drawable.s28,
R.drawable.s29,
R.drawable.s30,
R.drawable.s31,
R.drawable.s32,
R.drawable.s33,
R.drawable.s34,
R.drawable.s35,
};
private ArrayList mbitmap=新的ArrayList(mImageRes.length);
@凌驾
创建时受保护的void(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
最终处理程序=新处理程序();
mImageView=新的图像视图(此);
setContentView(mImageView);
线程重要=新线程(){
@凌驾
公开募捐{
长时间戳=System.currentTimeMillis();
for(int i=0;i
这在我的Nexus7上看起来相当不错,但加载所有位图确实需要4秒多一点的时间

你能提前加载位图吗

此外,它不会节省一吨,但你的PNG有一堆填充周围的透明空间。您可以裁剪它们并稍微减少内存。否则压缩图像也会有帮助(比如限制使用的颜色数量)

理想情况下,在上述解决方案中,您应该在位图不再使用后立即回收它们

另外,如果内存太大,你可以像你提到的那样做,并有一个位图缓冲区,但我很确定它需要3个以上的图像

祝你好运

编辑:尝试2。 首先,我将所有图像剪切到590x590。这使图像减少了大约1mb。然后我创建了一个新类,它有点“忙”,没有固定的帧速率,但在图像准备好后立即渲染图像:

package mk.testanimation;

import android.app.Activity;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Bundle;
import android.os.Handler;
import android.util.Log;
import android.widget.ImageView;

import java.util.ArrayList;

public class MainActivity extends Activity {
    ImageView mImageView;

    private int mImageRes[] = new int[]{R.drawable.s0, R.drawable.s1, R.drawable.s2, R.drawable.s3, R.drawable.s4, R.drawable.s5, R.drawable.s6, R.drawable.s7, R.drawable.s8, R.drawable.s9, R.drawable.s10, R.drawable.s11, R.drawable.s12, R.drawable.s13, R.drawable.s14, R.drawable.s15, R.drawable.s16, R.drawable.s17, R.drawable.s18, R.drawable.s19, R.drawable.s20, R.drawable.s21, R.drawable.s22, R.drawable.s23, R.drawable.s24, R.drawable.s25, R.drawable.s26, R.drawable.s27, R.drawable.s28, R.drawable.s29, R.drawable.s30, R.drawable.s31, R.drawable.s32, R.drawable.s33, R.drawable.s34, R.drawable.s35};

    private ArrayList<Bitmap> mBitmaps = new ArrayList<Bitmap>(mImageRes.length);

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        final long timestamp = System.currentTimeMillis();
        final Handler handler = new Handler();
        mImageView = new ImageView(this);
        setContentView(mImageView);
        Thread important = new Thread() {
            @Override
            public void run() {
                for (int i = 0; i < mImageRes.length; i++) {
                    mBitmaps.add(BitmapFactory.decodeResource(getResources(), mImageRes[i]));
                }
            }
        };
        important.setPriority(Thread.MAX_PRIORITY);
        important.start();
        Thread drawing = new Thread() {
            @Override
            public void run() {
                int i = 0;
                while (i < mImageRes.length) {
                    if (i >= mBitmaps.size()) {
                        Thread.yield();
                    } else {
                        final Bitmap bitmap = mBitmaps.get(i);
                        handler.post(new Runnable() {
                            @Override
                            public void run() {
                                mImageView.setImageBitmap(bitmap);
                            }
                        });
                        i++;
                    }
                }
                Log.d("ANIM-TAG", "Time to render all frames:" + (System.currentTimeMillis() - timestamp) + "ms");
            }
        };
        drawing.setPriority(Thread.MAX_PRIORITY);
        drawing.start();
    }
}
包mk.testanimation;
导入android.app.Activity;
导入android.graphics.Bitmap;
导入android.graphics.BitmapFactory;
导入android.os.Bundle;
导入android.os.Handler;
导入android.util.Log;
导入android.widget.ImageView;
导入java.util.ArrayList;
公共类MainActivity扩展了活动{
图像视图;
私有整数图像[]=新整数[]{R.drawable.s0,R.drawable.s1,R.drawable.s2,R.drawable.s3,R.drawable.s4,R.drawable.s5,R.drawable.s6,R.drawable.s7,R.drawable.s8,R.drawable.s9,R.drawable.s10,R.drawable.s11,R.s12,R.drawable.s13,R.drawable.s14,R.s15,R.drawable.s16,R.s17,R.drawable.s18,R.s10,R.s21,R.drawable.s21,R
long time = System.currentTimeMillis();
try {
    for (int i = 0; i < 35; i++) {
        InputStream assetStream = getAssets().open(
                "_step" + (i + 1) + ".png");
        try {
            Bitmap bitmap = BitmapFactory.decodeStream(assetStream);
            if (bitmap == null) {
                throw new RuntimeException("Could not load bitmap");
            }
            mBitmaps.add(bitmap);
        } finally {
            assetStream.close();
        }
    }
} catch (Exception e) {
    throw new RuntimeException(e);
}
Log.d("ANIM", "Loading bitmaps elapsed "+(System.currentTimeMillis() - time)+"ms");
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();
        }

    });