####帧动画导致的OOM
参考文章:https://www.jianshu.com/p/edcca8d3dd00
Re-using Bitmaps (100 Days of Google Dev) https://www.youtube.com/watch?v=_ioFW3cyRV0
extending the concept of object pools to bitmaps.
object pools are a common technique for high-chrun
data types.
signal to the decoder to use an existing piece
of memory to load that bitmap into.
reused bitmaps have a constraint with respect
to the physical size of the existing bitmaps.
SDK <= 18,the bitmap you're loading in and the bitmap
you're reusing must be the same exact size in order for
things to work properly.
SDK >= 19,existing bitmap can be >= incoming bitmap.
背景:最近项目里需要弄一个界面,基本没法用代码写,于是用帧动画,有33个图片.
开始没发现什么问题,直到有一次运行在三星s7上,OOM了我才意识到问题.
才想起来去看看AnimationDrawable相关的代码.
# AnimationDrawable.java
private AnimationState mAnimationState;
public void addFrame(@NonNull Drawable frame, int duration) {
mAnimationState.addFrame(frame, duration);
if (!mRunning) {
setFrame(0, true, false);
}
}
private final static class AnimationState extends DrawableContainerState{
public void addFrame(Drawable dr, int dur) {
// Do not combine the following. The array index must be evaluated before
// the array is accessed because super.addChild(dr) has a side effect on mDurations.
int pos = super.addChild(dr);
mDurations[pos] = dur;
}
}
DrawableContainerState.java
Drawable[] mDrawables;
public final int addChild(Drawable dr) {
final int pos = mNumChildren;
if (pos >= mDrawables.length) {
growArray(pos, pos+10);
}
dr.mutate();
dr.setVisible(false, true);
dr.setCallback(mOwner);
mDrawables[pos] = dr;
mNumChildren++;
mChildrenChangingConfigurations |= dr.getChangingConfigurations();
invalidateCache();
mConstantPadding = null;
mCheckedPadding = false;
mCheckedConstantSize = false;
mCheckedConstantState = false;
return pos;
}
通过查看代码可以发现,大致就是你创建DrawableAnimation然后再addFrame(Drawable dr,int dur). 一直不停的addFrame就会导致底层drawable数组不停线性变大. 这个过程是没法避免的,你要用帧动画的画就只能这样,导致在初始化的时候一下子干掉一大坨内存.
于是想办法优化.
-
刚开始想的DrawableAnimation是不是有一种方式,好比我三十个帧,每次只用5帧,然后本来30帧的动画我通过6次5帧的动画来实现. 这样就一直只有6个drawable.
-
后来上网搜发现有一个叫surfaceview的东西,允许你在非主线程更新界面. 大致意思就是通过Surfaceview来draw的drawable可以不在主线程中.一想本来主线程就有好多事情干,同样是draw各种drawable,如果能不在主线程就不在主线程吧.于是放弃第1个方案,折腾SurfaceView.