项目遭遇
实现帧动画,我一开始想到的是直接通过animation-list将全部图片按顺序放入,并设置时间间隔和播放模式。然后将该drawable设置给ImageView,然后就可以了
后来事情也正如所料的一样,完美加载出来了
AnimationDrawable animationDrawable;
if (imageView.getDrawable() == null) {
imageView.setImageResource(R.drawable.score_anim);
animationDrawable =(AnimationDrawable)imageView.getDrawable();
}
animationDrawable.start();//开始
animationDrawable.stop();//结束
但是到了后面,我工程的多个地方需要加载动画,发现直接oom.查看源码发现,是一次导入全部图片才会产生.
然后对源码的动画加载机制进行优化.
然后还做了一系列的封装.这其中,into的时候,会默认加载第一帧,在initDrawableList的时候,第一个参数就是动画的时间.第二个参数是动画资源的数组.我做了可变参数的处理
AnimationManager animationManager = AnimationManager.getInstance().initDrawableList(80,
R.drawable.score_0,
R.drawable.score_1,
R.drawable.score_2,
R.drawable.score_3,
R.drawable.score_4,
R.drawable.score_5,
R.drawable.score_6,
R.drawable.score_7,
R.drawable.score_8,
R.drawable.score_9,
R.drawable.score_11,
R.drawable.score_12,
R.drawable.score_13,
R.drawable.score_14,
R.drawable.score_15,
R.drawable.score_16,
R.drawable.score_17,
R.drawable.score_18,
R.drawable.score_19,
R.drawable.score_20,
R.drawable.score_21,
R.drawable.score_22,
R.drawable.score_23,
R.drawable.score_24,
R.drawable.score_25
).into(close);
animationManager.start();
这样就非常完美的播放出帧动画,并且不会有内存溢出的出现.这边采用了rxjava处理,如果项目不使用,则可以改成线程和切换线程的处理方式.
附上AnimationManager源码
public class AnimationManager {
private static AnimationManager sAnimationManager;
private Handler mHandler = new Handler(Looper.getMainLooper());
private long fps;
private int[] res;
private int oneImage;
private int count = 1;
private int length = 0;
private ImageView intoView;
private Bitmap nextBitmap;
private Bitmap currentBitmap;
private Disposable mSubscribe;
private AnimationManager() {
}
public static AnimationManager getInstance() {
if (sAnimationManager == null) {
sAnimationManager = new AnimationManager();
}
return sAnimationManager;
}
public AnimationManager initDrawableList(long fps, int... Res) {
this.fps = fps;
this.res = Res;
count = 1;
if (Res.length == 0) {
throw new RuntimeException("不能是空数组");
}
this.oneImage = Res[0];
length = Res.length;
return this;
}
public AnimationManager into(ImageView view) {
this.intoView = view;
// 加载第一张
Observable.just(oneImage)
.observeOn(Schedulers.io())
.map(new Function() {
@Override
public Bitmap apply(Integer integer) throws Exception {
BitmapFactory.Options opts = getOptions(integer);
// 加载下一张
if (res.length > 1) {
nextBitmap = BitmapFactory.decodeResource(intoView.getResources(), res[count++], opts);
}
return BitmapFactory.decodeResource(intoView.getResources(), integer, opts);
}
})
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Consumer() {
@Override
public void accept(Bitmap bitmap) throws Exception {
intoView.setImageBitmap(bitmap);
}
});
return this;
}
@NonNull
private BitmapFactory.Options getOptions(Integer integer) {
/**
* 先获取图片的和IamgeView各自的宽高
*/
BitmapFactory.Options opts = new BitmapFactory.Options();
//给opts配置只获取图片的元数据
opts.inJustDecodeBounds = true;
//注意:由于配置了opts并且是仅仅获取图片边界的属性,因此该方法返回的对象永远为null
BitmapFactory.decodeResource(intoView.getResources(), integer, opts);
//从opts对象上获取图片的宽高
int width = opts.outWidth;
int height = opts.outHeight;
int width1 = ScreenUtils.getScreenWidth(intoView.getContext());
int height1 = ScreenUtils.getScreenHeight(intoView.getContext());
int sampleSize = Math.max(width / width1, height / height1);
opts.inJustDecodeBounds = false;//必须配置为加载图片,而不是仅仅获取图片的尺寸
opts.inSampleSize = sampleSize; //配置等比例缩放的倍数
return opts;
}
public synchronized void start() {
mSubscribe = Observable.interval(fps, TimeUnit.MILLISECONDS)
.observeOn(Schedulers.io())
.map(new Function() {
@Override
public Boolean apply(Long aLong) throws Exception {
count++;
if (nextBitmap != null) {
currentBitmap = nextBitmap;
}
if (count > res.length - 1) {
return false;
}
BitmapFactory.Options opts = getOptions(res[count]);
nextBitmap = BitmapFactory.decodeResource(intoView.getResources(), res[count], opts);
return true;
}
})
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Consumer() {
@Override
public void accept(Boolean flag) throws Exception {
if (flag) {
intoView.setImageBitmap(currentBitmap);
} else {
mSubscribe.dispose();
}
}
});
}
}