Frame animation frame by frame memory OOM and resolve SurfaceView

 Frame animation memory OOM? nonexistent! - SurfaceView analytic frame by frame - https://juejin.im/post/5ccc1dcbe51d456e8b07ddf4
 . Play Frame Animation by SurfaceView the Get RID of OOM Due to Complex Frame Animation- https://github.com/wisdomtl/FrameSurfaceView/tree/master
 Android It provides AnimationDrawable used to achieve frame animation. Before the beginning of the animation, images of all the frames are parsed and take up memory, once more complex animation frames are more likely to occur on low OOM phone. Even OOM does not occur, it can also cause considerable pressure on memory.

- 原生帧动画AnimationDrawable
AnimationDrawable drawable = new AnimationDrawable();
drawable.addFrame(getDrawable(R.drawable.frame1), frameDuration);
drawable.addFrame(getDrawable(R.drawable.frame2), frameDuration);
drawable.addFrame(getDrawable(R.drawable.frame3), frameDuration);
drawable.addFrame(getDrawable(R.drawable.frame4), frameDuration);
drawable.setOneShot(true);

ImageView ivFrameAnim = ((ImageView) findViewById(R.id.frame_anim));
ivFrameAnim.setImageDrawable(drawable);
drawable.start();

 Is there any way to get the data frame of the animation frame by frame to load, but not loaded into memory all at once? SurfaceView provides this capability.
 To display a required calculation and rendering undergo two processes, CPU took the image data is calculated and written into the frame memory, and then call the OpenGL command-memory data stored in the image rendered in the GPU Buffer, every display device Buffer acquire images from a certain time and displayed.

- Frame SurfaceView parsing custom templates SurfaceView Code:
public abstract class BaseSurfaceView the extends SurfaceView the implements SurfaceHolder.Callback {
    public static int DEFAULT_FRAME_DURATION_MILLISECOND Final = 50;
    // the frame data for calculating the thread
    Private and HandlerThread HandlerThread;
    Private Handler Handler;
    // the frame refresh frequency
    Private frameDuration int = DEFAULT_FRAME_DURATION_MILLISECOND;
    // draw a canvas frame
    Private the canvas canvas;
    Private isAlive Boolean;

    public BaseSurfaceView(Context context) {
        super(context);
        init();
    }

    void the init protected () {
        getHolder () the addCallback (the this);.
        // a transparent background, the background is black or SurfaceView
        setBackgroundTransparent ();
    }

    private void setBackgroundTransparent() {
        getHolder().setFormat(PixelFormat.TRANSLUCENT);
        setZOrderOnTop(true);
    }

    @Override
    public void surfaceCreated(SurfaceHolder holder) {
        isAlive = true;
        startDrawThread();
    }

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

    @Override
    public void surfaceDestroyed(SurfaceHolder holder) {
        stopDrawThread();
        isAlive = false;
    }

    // Draw thread stop frame
    Private void stopDrawThread () {
        handlerThread.quit ();
        Handler = null;
    }

    //启动帧绘制线程
    private void startDrawThread() {
        handlerThread = new HandlerThread("SurfaceViewThread");
        handlerThread.start();
        handler = new Handler(handlerThread.getLooper());
        handler.post(new DrawRunnable());
    }

    private class DrawRunnable implements Runnable {

        @Override
        public void RUN () {
            IF (! IsAlive) {
                return;
            }
            the try {
                .. 1 // Get the canvas
                Canvas = getHolder () lockCanvas ();.
                . 2 // draw a
                onFrameDraw (Canvas);
            } the catch ( E Exception) {
                e.printStackTrace ();
            } {the finally
                . //. 3 frame data submitted
                getHolder () unlockCanvasAndPost (Canvas);.
                //. 4 a rendering end.
                onFrameDrawFinish ();
            }
            // stop their pushed to draw thread's message queue to achieve a frame refresh
            handler.postDelayed(this, frameDuration);
        }
    }
    
    protected abstract void onFrameDrawFinish();

    protected abstract void onFrameDraw(Canvas canvas);
}

- 逐帧解析 & 及时回收
public class FrameSurfaceView extends BaseSurfaceView {
    public static final int INVALID_BITMAP_INDEX = Integer.MAX_VALUE;
    private List<Integer> bitmaps = new ArrayList<>();
    private Bitmap frameBitmap;
    private int bitmapIndex = INVALID_BITMAP_INDEX;
    private Paint paint = new Paint();
    private BitmapFactory.Options options;
    private Rect srcRect;
    private Rect dstRect = new Rect();

    public void setDuration(int duration) {
        int frameDuration = duration / bitmaps.size();
        setFrameDuration(frameDuration);
    }

    public void setBitmaps(List<Integer> bitmaps) {
        if (bitmaps == null || bitmaps.size() == 0) {
            return;
        }
        this.bitmaps = bitmaps;
        getBitmapDimension(bitmaps.get(0));
    }

    private void getBitmapDimension(Integer integer) {
        final BitmapFactory.Options options = new BitmapFactory.Options();
        options.inJustDecodeBounds = true;
        BitmapFactory.decodeResource(this.getResources(), integer, options);
        defaultWidth = options.outWidth;
        defaultHeight = options.outHeight;
        srcRect = new Rect(0, 0, defaultWidth, defaultHeight);;
    }

    public FrameSurfaceView(Context context) {
        super(context);
    }

    @Override
    protected void the init () {
        the super.init ();
        // parse Bitmap parameter defined variable type, in order to reuse Bitmap
        Options new new BitmapFactory.Options = ();
        options.inMutable = to true;
    }

    @Override
    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
        super.onLayout(changed, left, top, right, bottom);
        dstRect.set(0, 0, getWidth(), getHeight());
    }

    @Override
    protected int getDefaultWidth() {
        return defaultWidth;
    }

    @Override
    protected int getDefaultHeight() {
        return defaultHeight;
    }

    @Override
    protected void onFrameDrawFinish () {
        // for each frame drawing After completion of recovery is no longer
// Recycle ();
    }

    public void recycle() {
        if (frameBitmap != null) {
            frameBitmap.recycle();
            frameBitmap = null;
        }
    }

    @Override
    protected void onFrameDraw(Canvas canvas) {
        clearCanvas(canvas);
        if (!isStart()) {
            return;
        }
        if (!isFinish()) {
            drawOneFrame(canvas);
        } else {
            onFrameAnimationEnd();
        }
    }

    void drawOneFrame Private (the Canvas Canvas) {
        frameBitmap = BitmapUtil.decodeOriginBitmap (getResources (),
        // re spend a Bitmap memory
        bitmaps.get (bitmapIndex), Options);
        options.inBitmap = frameBitmap;
        Canvas.drawBitmap (frameBitmap, srcRect, dstRect, Paint);
        bitmapIndex ++;
    }

    private void onFrameAnimationEnd() {
        reset();
    }

    private void reset() {
        bitmapIndex = INVALID_BITMAP_INDEX;
    }

    private boolean isFinish() {
        return bitmapIndex >= bitmaps.size();
    }

    private boolean isStart() {
        return bitmapIndex != INVALID_BITMAP_INDEX;
    }

    public void start() {
        bitmapIndex = 0;
    }

    private void clearCanvas(Canvas canvas) {
        paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));
        canvas.drawPaint(paint);
        paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC));
    }
}

Guess you like

Origin blog.csdn.net/ShareUs/article/details/89841854