欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

帧动画多线程加载

程序员文章站 2022-03-02 08:18:05
...

帧动画在使用时,很容易造成卡顿。此代码使用多线程动态加载,防止卡顿。

使用方法:

int[] right_res_id = new int[]{R.drawable.r_00072, R.drawable.r_00073, R.drawable.r_00074, R.drawable.r_00075};

final AnimationsContainer.FramesSequenceAnimation rightAnim =               
        AnimationsContainer.getInstance(this,right_res_id,58).createProgressDialogAnim(imgRight);

rightAnim.setOnAnimStopListener(new AnimationsContainer.OnAnimationStoppedListener() {
            @Override
            public void AnimationStopped() {
                // TODO
            }
        });
//rightAnim.loop(true);
//rightAnim.stop();
rightAnim.start();

代码 AnimationsContainer.java

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.drawable.BitmapDrawable;
import android.os.Build;
import android.os.Handler;
import android.widget.ImageView;

import java.lang.ref.SoftReference;

/**
 * 帧动画加载器
 */

public class AnimationsContainer {
    private int DelayMillis = 58;  // 每帧播放时间,毫秒
    private int[] resId;
    private Context mContext;
    // 单例
    private static final AnimationsContainer mInstance = new AnimationsContainer();


    private AnimationsContainer() {
    }

    //获取单例
    public static AnimationsContainer getInstance(Context context, int[] resId, int fps) {
        mInstance.setResId(context, resId, fps);
        return mInstance;
    }

    private void setResId(Context context, int[] resId, int delayMillis) {
        this.mContext = context;
        this.resId = resId;
        this.DelayMillis = delayMillis;
    }

    /**
     * @param imageView
     * @return progress dialog animation
     */
    public FramesSequenceAnimation createProgressDialogAnim(ImageView imageView) {
        return new FramesSequenceAnimation(imageView, resId, DelayMillis);
    }


    /**
     * 循环读取帧---循环播放帧
     */
    public class FramesSequenceAnimation {
        private int[] mFrames; // 帧数组
        private int mIndex; // 当前帧
        private boolean mShouldRun; // 开始/停止播放用
        private boolean mIsRunning; // 动画是否正在播放,防止重复播放
        private SoftReference<ImageView> mSoftReferenceImageView; // 软引用ImageView,以便及时释放掉
        private Handler mHandler;
        private int mDelayMillis;
        private boolean isLoop = false;
        private OnAnimationStoppedListener mOnAnimationStoppedListener; //播放停止监听

        private Bitmap mBitmap = null;
        private BitmapFactory.Options mBitmapOptions;//Bitmap管理类,可有效减少Bitmap的OOM问题

        public FramesSequenceAnimation(ImageView imageView, int[] frames, int mDelayMillis) {
            mHandler = new Handler();
            mFrames = frames;
            mIndex = -1;
            mSoftReferenceImageView = new SoftReference<ImageView>(imageView);
            mShouldRun = false;
            mIsRunning = false;
            this.mDelayMillis = mDelayMillis;//帧动画时间间隔,毫秒

            imageView.setImageResource(mFrames[0]);

            // 当图片大小类型相同时进行复用,避免频繁GC
            if (Build.VERSION.SDK_INT >= 11) {
                Bitmap bmp = ((BitmapDrawable) imageView.getDrawable()).getBitmap();
                int width = bmp.getWidth();
                int height = bmp.getHeight();
                Bitmap.Config config = bmp.getConfig();
                mBitmap = Bitmap.createBitmap(width, height, config);
                mBitmapOptions = new BitmapFactory.Options();
                //设置Bitmap内存复用
                mBitmapOptions.inBitmap = mBitmap;//Bitmap复用内存块,类似对象池,避免不必要的内存分配和回收
                mBitmapOptions.inMutable = true;//解码时返回可变Bitmap
                mBitmapOptions.inSampleSize = 1;//缩放比例
            }
        }

        //循环读取下一帧
        private int getNext() {
            mIndex++;
            if (mIndex<mFrames.length){
                return mFrames[mIndex];
            }else if (mIndex >= mFrames.length && isLoop) {
                return mIndex = 0;
            } else{
                stop();
                return mIndex = 0;
            }
        }

        /**
         * 播放动画,同步锁防止多线程读帧时,数据安全问题
         */
        public synchronized void start() {
            mShouldRun = true;
            if (mIsRunning)
                return;

            Runnable runnable = new Runnable() {
                @Override
                public void run() {
                    ImageView imageView = mSoftReferenceImageView.get();
                    if (!mShouldRun || imageView == null) {
                        mIsRunning = false;
                        if (mOnAnimationStoppedListener != null) {
                            mOnAnimationStoppedListener.AnimationStopped();
                        }
                        return;
                    }

                    mIsRunning = true;
                    //新开线程去读下一帧
                    mHandler.postDelayed(this, mDelayMillis);

                    if (imageView.isShown()) {
                        int imageRes = getNext();
                        if (mBitmap != null) { // so Build.VERSION.SDK_INT >= 11
                            Bitmap bitmap = null;
                            try {
                                bitmap = BitmapFactory.decodeResource(imageView.getResources(), imageRes, mBitmapOptions);
                            } catch (Exception e) {
                                e.printStackTrace();
                            }
                            if (bitmap != null) {
                                imageView.setImageBitmap(bitmap);
                            } else {
                                imageView.setImageResource(imageRes);
                                mBitmap.recycle();
                                mBitmap = null;
                            }
                        } else {
                            imageView.setImageResource(imageRes);
                        }
                    }

                }
            };

            mHandler.post(runnable);
        }

        /**
         * 停止播放
         */
        public synchronized void stop() {
            mShouldRun = false;
        }

        public synchronized void loop(boolean isLoop) {
            this.isLoop = isLoop;
        }

        /**
         * 设置停止播放监听
         *
         * @param listener
         */
        public void setOnAnimStopListener(OnAnimationStoppedListener listener) {
            this.mOnAnimationStoppedListener = listener;
        }
    }

    /**
     * 停止播放监听
     */
    public interface OnAnimationStoppedListener {
        void AnimationStopped();
    }
}

 

相关标签: 帧动画