欢迎使用CSDN-markdown编辑器

关于Android帧动画加载多张图片OOM问题

Android的手机当你的一个imagerview一次加载超过20多张图片时,如果你的手机运行内存低于1G,当你播放两次后,基本会报OOM,这里就可可以采用SurfaceView,这里有个要注意的是surfaceDestroyed这个方法。当视图消失就会调用,问题就在这里了。当你点击HOME键的时候,调用surfaceDestroyed方法。而如果您像我一样在这里做了线程的停止,千万记得在surfaceCreated这里做你要恢复的操作。

不多说直接上代码,代码里解释的很清楚了
/**
* 自定义帧动画播放view,完美解决原生帧动画OOM问题
* @author 小袁
*
*/
public class FrameAnimationView extends SurfaceView implements SurfaceHolder.Callback, Runnable {

private SurfaceHolder mSurfaceHolder;

private boolean mIsThreadRunning = true; // 线程运行开关
private boolean mIsDestroy = false;// 是否已经销毁

private int[] mBitmapResourceIds;// 用于播放动画的图片资源数组
private Canvas mCanvas;
private Bitmap mBitmap;// 显示的图片

private int mCurrentIndext;// 当前动画播放的位置
private int mGapTime = 40;// 每帧动画持续存在的时间

private OnFrameFinishedListener mOnFrameFinishedListener;// 动画监听事件

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

public FrameAnimationView(Context context, AttributeSet attrs, int defStyle)
{
    super(context, attrs, defStyle);
    mSurfaceHolder = this.getHolder();
    mSurfaceHolder.addCallback(this);// 注册回调方法

    // 白色背景
    setZOrderOnTop(true);
    mSurfaceHolder.setFormat(PixelFormat.TRANSLUCENT);
}

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

@Override
public void surfaceCreated(SurfaceHolder holder)
{
    // 创建surfaceView时启动线程
    mIsDestroy = false;
}

@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height)
{
}

@Override
public void surfaceDestroyed(SurfaceHolder holder)
{
    Log.e("[ZOZO]", "surfaceDestroyed被销毁了");
    // 当surfaceView销毁时, 停止线程的运行. 避免surfaceView销毁了线程还在运行而报错.
    mIsThreadRunning = false;
    try
    {
        Thread.sleep(mGapTime);
    } catch (InterruptedException e)
    {
        e.printStackTrace();
    }

    mIsDestroy = true;
}

/**
 * 制图方法
 */
private void drawView()
{
    // 无资源文件退出
    if (mBitmapResourceIds == null)
    {
        Log.e("[ZOZO]", "the bitmapsrcIDs is null");

        mIsThreadRunning = false;

        return;
    }

    // 锁定画布
    mCanvas = mSurfaceHolder.lockCanvas();
    try
    {
        if (mSurfaceHolder != null && mCanvas != null)
        {

            mCanvas.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR);


            // 如果图片过大可以再次对图片进行二次采样缩放处理
            mBitmap = BitmapFactory.decodeResource(getResources(), mBitmapResourceIds[mCurrentIndext]);
            mCanvas.drawBitmap(mBitmap, (getWidth() - mBitmap.getWidth()) / 2,
                    (getHeight() - mBitmap.getHeight()) / 2, null);

            // 播放到最后一张图片,停止线程
            if (mCurrentIndext == mBitmapResourceIds.length - 1)
            {
                mIsThreadRunning = false;
            }

        }
    } catch (Exception e)
    {
        e.printStackTrace();
    } finally
    {
        mCurrentIndext++;

        if (mCanvas != null)
        {
            // 将画布解锁并显示在屏幕上
            mSurfaceHolder.unlockCanvasAndPost(mCanvas);
        }

        if (mBitmap != null)
        {
            // 收回图片
            mBitmap.recycle();
        }
    }
}

@Override
public void run()
{
    if (mOnFrameFinishedListener != null)
    {
        mOnFrameFinishedListener.onStart();
    }

    // 每隔100ms刷新屏幕
    while (mIsThreadRunning)
    {
        drawView();
        try
        {
            Thread.sleep(mGapTime);
        } catch (Exception e)
        {
            e.printStackTrace();
        }
    }

    if (mOnFrameFinishedListener != null)
    {
        mOnFrameFinishedListener.onStop();
    }
}

/**
 * 开始动画
 */
public void start()
{
    if (!mIsDestroy)
    {
        Log.e("[ZOZO]", "驱动了");
        mCurrentIndext = 0;
        mIsThreadRunning = true;
        new Thread(this).start();
    } else
    {
        Log.e("[ZOZO]", "驱动出错了");
        // 如果SurfaceHolder已经销毁抛出该异常
        try
        {
            throw new Exception("IllegalArgumentException:Are you sure the SurfaceHolder is not destroyed");
        } catch (Exception e)
        {
            e.printStackTrace();
        }
    }
}

/**
 * 设置动画播放素材
 * @param bitmapResoursIds  图片资源id
 */
public void setBitmapResoursID(int[] bitmapResourceIds)
{
    this.mBitmapResourceIds = bitmapResourceIds;
}

/**
 * 设置每帧时间
 */
public void setGapTime(int gapTime)
{
    this.mGapTime = gapTime;
}

/**
 * 结束动画
 */
public void stop()
{
    mIsThreadRunning = false;
}

/**
 * 继续动画
 */
public void reStart()
{
    mIsThreadRunning = false;
}

/**
 * 设置动画监听器
 */
public void setOnFrameFinisedListener(OnFrameFinishedListener onFrameFinishedListener)
{
    this.mOnFrameFinishedListener = onFrameFinishedListener;
}

/**
 * 动画监听器
 * @author qike
 *
 */
public interface OnFrameFinishedListener {

    /**
     * 动画开始
     */
    void onStart();

    /**
     * 动画结束
     */
    void onStop();
}

/**
 * 当用户点击返回按钮时,停止线程,反转内存溢出
 */
@Override
public boolean onKeyDown(int keyCode, KeyEvent event)
{
    // 当按返回键时,将线程停止,避免surfaceView销毁了,而线程还在运行而报错
    if (keyCode == KeyEvent.KEYCODE_BACK)
    {
        mIsThreadRunning = false;
    }

    return super.onKeyDown(keyCode, event);
}

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值