canvas drawbitmap不出现_大图做帧动画就卡顿?不存在的!

原创作者:唐子玄

https://juejin.im/post/5cd240f2e51d453afb40d83a

本文由作者授权发布。

继上篇用“SurfaceView逐帧解析 & 帧复用”优化了帧动画内存性能后,一个更复杂的问题浮出水面:帧动画时间性能。

这一篇试着让每帧素材大小 1MB 的帧动画流畅播放的同时不让内存膨胀。在整个优化过程中,综合运用了多线程、阻塞队列、消息机制、滑动窗口机制。也体悟到了计算机设计的中庸之道。

在此要感谢评论上一篇文章的掘友“小前锋”,是你的提问指引了我在这个方向上继续探索。

(ps:粗斜体表示引导方案逐步进化的关键点)

壹·SurfaceView逐帧解析 & 帧复用

简单回顾下上一篇的内容:原生帧动画在播放前解析所有帧,对内存压力大。SurfaceView可以精细地控制帧动画每一帧的绘制,在每一帧绘制前才解析当前帧,且解析后续帧时复用前帧内存空间。

遂整个过程在内存只申请了一帧图片大小的空间。下面罗列了一些关键代码:

基类:定义绘制框架

基类:定义绘制框架
public abstract class BaseSurfaceView extends SurfaceView implements SurfaceHolder.Callback {
    ...
    //绘制线程
    private HandlerThread handlerThread;
    private Handler handler;

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

    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() {
            try {
                canvas = getHolder().lockCanvas();
                //绘制一帧,包括解码+绘制帧
                onFrameDraw(canvas);
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                getHolder().unlockCanvasAndPost(canvas);
                onFrameDrawFinish();
            }
            //若onFrameDraw()执行超时,会导致下一帧的绘制被推后,预定的帧时间间隔不生效
            handler.postDelayed(this, frameDuration);
        }
    }

    protected abstract void onFrameDraw(Canvas canvas);
}

//帧动画绘制类:将绘制内容具体化为一张Bitmap
public class FrameSurfaceView extends BaseSurfaceView {
    ...
    private BitmapFactory.Options options;

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

    private void drawOneFrame(Canvas canvas) {
        //解析帧
        frameBitmap = BitmapFactory.decodeResource(getResources(), bitmaps.get(bitmapIndex), options);
        //复用帧
        options.inBitmap = frameBitmap;
        //绘制帧
        canvas.drawBitmap(frameBitmap, srcRect, dstRect, paint);
        bitmapIndex++;
    }
    ...

贰·对比图片解析速度

对于素材在 100k 以下的帧动画,上一篇的逐帧解析方案完全能够胜任。但如果素材是几百k,时间性能就不如预期。

掘友“小前锋”问:“你的方案有测试过大图吗?比如1024*768px”

在逐帧解析SurfaceView上试了下这个大小的帧动画,虽然播放过程很连续,但 600ms 的帧动画被放成了 1s。因为预定义的每帧播放时间被解码时间拉长了。

有没有比BitmapFactory.decodeResource()更快的解码方式?

于是乎对比了各种图片解码的速度,其中包括BitmapFactory

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值