android 帧动画张数限制,帧动画优化思路
Android 帧动画(Frame Animation)的使用十分简单定义 Animation-List 资源 res/anim/rocket.xml1234567android:oneshot="false">设置到 ImageView12345ImageView rocketImage = (ImageView) findViewById(R.id.rocket_image);rocke
Android 帧动画(Frame Animation)的使用十分简单
定义 Animation-List 资源 res/anim/rocket.xml
1
2
3
4
5
6
7<?xml version="1.0" encoding="utf-8"?>
android:oneshot="false">
设置到 ImageView
1
2
3
4
5ImageView rocketImage = (ImageView) findViewById(R.id.rocket_image);
rocketImage.setBackgroundResource(R.drawable.rocket_thrust);
rocketAnimation = (AnimationDrawable) rocketImage.getBackground();
rocketAnimation.start();
但是,当你的帧动画比较长,例如有40张图片,而每张图片又比较大的时候就会很容易出现OOM。
显然 Animation-List 满足不了40张图片这种情况,40张图片就会占用40份内存,非常糟糕的内存占用。
解决方案: BitmapFactory.Options.inBitmap
从Android 3.0 (API Level 11)开始,引进了BitmapFactory.Options.inBitmap字段。
如果使用了这个设置字段,decode方法会在加载Bitmap数据的时候去重用已经存在的Bitmap。
这意味着Bitmap的内存是被重新利用的,这样可以提升性能,并且减少了内存的分配与回收。
然而,使用inBitmap有一些限制,特别是在Android 4.4 (API level 19)之前,只有同等大小的位图才可以被重用。详情请查看inBitmap文档。
使用该技术,在播放动画的时候只需要一份内存就可以了,重复使用 Bitmap 内存,连内存抖动都不会发生。
所以我的做法是自己实现动画播放: load resource -> decode(inBitmap) -> set to ImageView -> delay -> load resource -> …
要让动画流畅,需要确保 load resource 与 decode 的工作在16毫秒内完成,(16ms 来源)
16ms 优化思路:
load resource : 如果所有资源的大小加起来只有几Mb,则可以将资源缓存起来,事先把所有资源加载到内存,那后面解码的话将会很快。
根据实际业务真机测试下decode工作时间大概为多少,如果小于16ms,那就在主线程实现,如果decode耗时有点长,那就启用两个线程,使用两份内存(two inBitmap)。
主线程大致实现
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76public abstract class FrameAnimationHelper{
private byte bitmapBytes[][];
private int[] frames;
private Bitmap bitmap;
private ImageView imageView;
private BitmapFactory.Options options;
private int order = 0;
public FrameAnimationHelper(ImageView imageView){
this.imageView = imageView;
frames = getFrameResources();
if (frames == null || frames.length < 1) {
throw new RuntimeException("FrameAnimationHelper need frame resource");
}
bitmapBytes = new byte[frames.length][];
options = new BitmapFactory.Options();
options.inPreferredConfig = Bitmap.Config.ARGB_8888;
options.inMutable = true;
//load resource to memory
if (bitmapBytes[0] == null) {
Resources resources = imageView.getResources();
int bytesRead;
InputStream is;
ByteArrayOutputStream bos;
byte[] b = new byte[4096];
try {
for (int i = 0; i < frames.length; i++) {
is = resources.openRawResource(frames[i]);
bos = new ByteArrayOutputStream();
while ((bytesRead = is.read(b)) != -1) {
bos.write(b, 0, bytesRead);
}
bitmapBytes[i] = bos.toByteArray();
}
} catch (IOException e) {
}
}
imageView.setImageBitmap(decode(order));
}
public void start(){
if (order >= frames.length) {
order = 0;
}
imageView.post(runnable);
}
public void stop(){
imageView.removeCallbacks(runnable);
}
private Bitmap decode(int order){
if (order < frames.length) {
options.inBitmap = bitmap;
bitmap = BitmapFactory.decodeByteArray(bitmapBytes[order], 0, bitmapBytes[order].length, options);
}
return bitmap;
}
private Runnable runnable = new Runnable() {
@Override
public void run(){
if (order < frames.length) {
imageView.setImageBitmap(decode(order));
imageView.postDelayed(runnable, 16);
order++;
}
}
};
protected abstract int[] getFrameResources();
}
更多推荐
所有评论(0)