我试图通过改变图像视图中的图像来逐帧动画显示。我尝试在xml中绘制动画,并在Handler中更改imageview的位图。我还试图在arraylist中存储三个位图(以避免内存不足)作为缓存机制,但实际上是很低的改进。我需要迭代36张图像以获得完整的动画效果。我面临的问题是,在我使用的所有方法中,我无法在50ms的给定时间范围内完成动画。图像范围从最小250 kb到最大540 kb。动画的fps非常低。随着应用程序的ios版本准备就绪,我被限制为显示与ios版本一致的动画。我是renderscript和opengl的菜鸟。有没有办法在50-60ms内显示大图像的平滑动画。任何提示或建议都非常感谢。下面是动画的快照: 对于任何一个有兴趣的人来说,这是link我的图像。
答案 0 :(得分:9)
我写了一个简单的活动,它做了最基本的事情:
加载线程中的所有位图,然后每隔40ms将更改发布到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();
}
}
在我的Nexus 7上看起来相当不错,但加载所有位图确实需要4s多一点。
您可以提前加载位图吗?
此外,它不会节省一吨,但你的pngs在透明空间周围有一堆填充物。您可以裁剪它们并减少内存。否则压缩图像也会有所帮助(比如限制使用的颜色数量)。
理想情况下,在上述解决方案中,您可以在不再使用位图后立即回收这些位图。
另外,如果内存太大,你可以按照你的提法做,并有一个Bitmap缓冲区,但我很确定它需要超过3个图像大
祝你好运。编辑:尝试2。 首先,我将所有图像裁剪为590x590。这削减了大约1mb的图像。然后我创建了一个新课程,这是一个忙碌的&#34;并且没有固定的帧速率,但在图像准备就绪后立即呈现:
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();
}
}
上面的渲染几乎立即开始,我的2012 Nexus 7花了不到4秒。
作为最后的努力,我将所有图像转换为8位PNG而不是32位。这使得渲染不到2秒!
我敢打赌,你最终得到的任何解决方案都会受益于使图像尽可能小。
再次 - 祝你好运!
答案 1 :(得分:3)
我面临同样的问题,我通过覆盖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();
}
});
这就是全部,并且工作正常我!
答案 2 :(得分:1)
尝试为AnimationDrawable
使用ImageView
。例如,请参阅我的回答here。
答案 3 :(得分:1)
答案 4 :(得分:0)
使用编程创建一个imageView,然后用一个角度旋转它然后再制作另一个然后旋转它..为你要显示的imageView数量做。你只需要为它添加一个图像。 你可以像这样旋转图像..
Matrix matrix=new Matrix();
imageView.setScaleType(ScaleType.MATRIX); //required
matrix.postRotate((float) angle, pivX, pivY);
imageView.setImageMatrix(matrix);
答案 5 :(得分:0)
也许是愚蠢的答案,但它可能对你有所帮助。使用其他工具制作动画并将其保存为高质量视频,然后播放视频。
答案 6 :(得分:0)
尝试将图片导出为GIF? Android确实支持解码GIF文件。
答案 7 :(得分:0)
从资源而不是资源加载位图为我节省了40%的解码时间。你可能想尝试一下。
因此,在我的2012 Nexus 7上,你的照片上的资源从5秒增加到3秒:
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");