android SurfaceView 处理帧动画避免OOM

使用SurfaceView + LruCache的方式来进行对帧动画的处理,避免由于图片过多过大导致的OOM问题。

代码:


import android.content.Context;
import android.content.res.AssetManager;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.PorterDuff;
import android.graphics.Rect;
import android.util.AttributeSet;
import android.view.SurfaceHolder;
import android.view.SurfaceView;

import java.io.IOException;

public class BoSurfaceView extends SurfaceView implements SurfaceHolder.Callback {
    private Context mContext;
    /**
     * 画布
     */
    private Canvas canvas;
    /**
     * 绘制区域的矩形
     */
    private Rect rect;
    /**
     * 存放图片集合的文件夹路径 (我的在assets下 ,这个可以看着来)
     */
    private String parentFileName = "recordimg";
    /**
     * 图片缓存
     */
    private BoBitmapLruCache lruCache;
    private AssetManager assets;
    /**
     * 图片路径的数组
     */
    private String[] recordimgs;

    /**
     * 是否继续播放的开关
     */
    private boolean isStop = true;

    /**
     * 每秒播放的帧数
     */
    private int frameCount = 30;
    private SurfaceHolder holder;

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

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

    public BoSurfaceView(Context context, AttributeSet attrs, int defStyleAttr) {
        super( context, attrs, defStyleAttr );
        mContext = context;
        init();
    }



    private void init() {
        //创建出缓存对象。 区域为当前内存最大值的八分之一
        lruCache = new BoBitmapLruCache( (int) (Runtime.getRuntime().maxMemory() / 1024 / 8) );
        assets = mContext.getAssets();
        // 设置各种状态
        getHolder().addCallback( this );
        setFocusable( true );
        setFocusableInTouchMode( true );
        setKeepScreenOn( true );
        setZOrderMediaOverlay( true );
    }

    /**
     *   绘制的控制方法
     * @param holder
     * @param isinit  是否绘制第一条  用于初始化的时候绘制第一帧
     */
    private void onDrawControl(SurfaceHolder holder, boolean isinit) {
        new Thread( new Runnable() {
            @Override
            public void run() {
                try {
                    if (isinit) {
                        //绘制第一帧
                        draw( 0, holder );
                    } else {
                        //循环绘制
                        for (int i = 0; i < recordimgs.length; i++) {
                            if (!isStop) {
                                //绘制
                                draw( i, holder );
                                //计算帧数让线程休眠(不是很准确)
                                Thread.sleep( 1000 / frameCount );
                                //循环到最后的时候递归调用,用来循环播放
                                if (i == recordimgs.length - 1) {
                                    onDrawControl( holder, false );
                                }
                            } else {
                                //停止直接跳出循环(终止递归)
                                return;
                            }
                        }
                    }
                } catch (Exception e) {

                }

            }
        } ).start();


    }

    /**
     *  绘制
     * @param index  当前图片的下标
     * @param holder
     * @throws IOException
     */
    private void draw(int index, SurfaceHolder holder) throws IOException {
        // 获取画布
        canvas = holder.lockCanvas( rect );
        // 绘制背景
        canvas.drawColor( Color.WHITE, PorterDuff.Mode.SRC );
        //没有缓存的话就把Bitmap加入缓存
        if (lruCache.get( parentFileName + "/" + recordimgs[index] ) == null) {
            Bitmap bitmap = null;
            bitmap = BitmapFactory.decodeStream( assets.open( parentFileName + "/" + recordimgs[index] ) );
            lruCache.put( parentFileName + "/" + recordimgs[index], bitmap );
        }
        // 从缓存中取出bitmap进行绘制
        if (canvas != null) {
            canvas.drawBitmap( lruCache.get( parentFileName + "/" + recordimgs[index] ), null, rect, null );
            if (holder.getSurface().isValid()) {
                holder.unlockCanvasAndPost( canvas );
            }
        }
    }


    @Override
    public void surfaceCreated(SurfaceHolder holder) {
        this.holder = holder;

        rect = new Rect( getLeft(), getTop(), getRight(), getBottom() );
        try {
            //获取路径的数组
            recordimgs = assets.list( parentFileName );
            onDrawControl( holder, true );
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

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

    }

    @Override
    public void surfaceDestroyed(SurfaceHolder holder) {

        isStop = true;
        //销毁的时候手动调用下Gc
        Runtime.getRuntime().gc();
    }

    /**
     * 开始
     */
    public void start() {
        isStop = false;
        if (holder != null) {
            onDrawControl( holder, false );
        }
    }

    /**
     * 停止
     */
    public void stop() {
        isStop = true;
        Runtime.getRuntime().gc();
    }

BoBitmapLruCache :

import android.graphics.Bitmap;
import android.util.LruCache;

public class BoBitmapLruCache extends LruCache<String,Bitmap> {
    /**
     * @param maxSize for caches that do not override {@link #sizeOf}, this is
     *                the maximum number of entries in the cache. For all other caches,
     *                this is the maximum sum of the sizes of the entries in this cache.
     */
    public BoBitmapLruCache(int maxSize) {
        super( maxSize );
    }


    @Override
    protected int sizeOf(String key, Bitmap value) {
        return value.getByteCount() / 1024;
    }
}

你可能感兴趣的:(动画)