android 动画有几种不同的类型,其中有一种是帧动画。实现它的方式也有几种,一种是直接作出 gif 或 webP 格式的图片,直接播放;一种则是 android 系统提供封装好的方法,将动画定义在 xml 中,用 animation-list 标签来实现它,<animation-list> 元素是必要的,可以包含n个 <item> 元素,每个 item 代表一帧动画。 以上两种都能实现,但比较耗费内存,想想看,假如说帧动画有 100 张图片,每张图片都比较大的情况下,此时执行动画,瞬间加载这么多图片,内存会出现什么问题,很大的几率会 OOM。
 

有没有节省内存的方法?帧动画说白了就是固定时间的刷新一个ImageView,显示不同的图片,既然知道了这些,那么我们可以使用 Handler ,每隔100毫秒就发送一个通知,接收到通知后获取一个指定的图片资源,刷新到ImageView上面,这样就避免了瞬间加载多张图片资源的问题了;如果再进一步优化,我们可以获取图片资源时,使用缓存把获取到的图片存起来,这样就不必每次都从资源里面获取,先判断缓存中有没有;再进一步,我们可以把中封装起来,熟悉自定义控件的同学,我们可以直接继承 View,来实现这个逻辑。图片绘制说白了就是对 Drawable 的绘制,之前文章中也提到过,这里就不多说了,直接上代码,主要是提供一个思路。

 

public class AnimationView extends View {

    private final static String KEY_MARK = "0";

    private int[] mFrameRess;
    private int mDuration;
    private int mLastFrame;
    private int mCurrentFrame;
    private boolean mPause;
    private Rect mDst;
    private BitmapLRU mLruCache;

    public AnimationView(Context context) {
        this(context, null);
    }

    public AnimationView(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public AnimationView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init(context, attrs);
    }

    private void init(Context context, AttributeSet attrs) {
        TypedArray typedArray = getResources().obtainTypedArray(R.array.animation_1);
        int len = typedArray.length();
        int[] resId = new int[len];
        for (int i = 0; i < len; i++) {
            resId[i] = typedArray.getResourceId(i, -1);
        }
        typedArray.recycle();

        this.mFrameRess = resId;
        this.mDuration = 50;
        this.mLastFrame = resId.length - 1;

        mLruCache = BitmapLRU.getInstance();
    }


    @Override
    protected void onDetachedFromWindow() {
        super.onDetachedFromWindow();
        pauseAnimation();
    }


    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
        mDst = new Rect(0, 0, w, h);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);

        canvas.save();
        Drawable d = takeDrawable();
        d.setBounds(mDst);
        d.draw(canvas);
        canvas.restore();

    }

    private Drawable takeDrawable(){
        int resid = mFrameRess[mCurrentFrame];
        String key = KEY_MARK + resid;
        Drawable drawable = mLruCache.get(key);
        if(drawable == null){
            drawable = getResources().getDrawable(resid);
            mLruCache.put(key, drawable);
        }
        return drawable;
    }




    public void play(final int i) {
        postDelayed(new Runnable() {

            @Override
            public void run() {
                mCurrentFrame = i;
                if (mPause) {
                    return;
                }
                invalidate();
                if (i == mLastFrame) {
                    play(0);
                } else {
                    play(i + 1);
                }
            }
        }, mDuration);
    }


    public void pauseAnimation() {
        this.mPause = true;
    }


}
public class BitmapLRU {

    private int maxMemory = (int) Runtime.getRuntime().maxMemory();
    private int cacheSize = maxMemory / 18;
    private LruCache<String, Drawable> mCache;

    private BitmapLRU(){
        mCache = new LruCache<String, Drawable>(cacheSize){
            @Override
            protected int sizeOf(String key, Drawable value) {
                return value.getIntrinsicWidth() * value.getIntrinsicHeight();
            }
        };
    }

    private static BitmapLRU single = new BitmapLRU();

    public static BitmapLRU getInstance(){
        return single;
    }


    public void put(String key, Drawable value){
        mCache.put(key, value);
    }

    public Drawable get(String key){
        return mCache.get(key);
    }


}
<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:tools="http://schemas.android.com/tools" tools:ignore="MissingTranslation">
    

    <array name="animation_1">
        <item>@drawable/da_00</item>
        <item>@drawable/da_01</item>
        <item>@drawable/da_02</item>
        <item>@drawable/da_03</item>
        <item>@drawable/da_04</item>
        <item>@drawable/da_05</item>
        <item>@drawable/da_06</item>
        <item>@drawable/da_07</item>
        <item>@drawable/da_08</item>
        <item>@drawable/da_09</item>
        <item>@drawable/da_10</item>
    </array>

</resources>

在外面使用 animationView.play(0); 即可。