Android学习随笔(001) 简谈lockCanvas(Rect dirty)

        昨天刚开始摸索Surface这个东西,在用到 lockCanvas(Rect dirty)这个接口的时候一直没有出来自己想要的效果,网上搜了一下不得要领,后来看到“双缓冲”这几个字突然蹦出来一丝灵感,加以实践,最终证实了自己的猜想。

 

        lockCanvas(null),就是锁住整张画布,绘画完成后也更新整张画布的内容到屏幕上,这个没有什么疑惑。而 lockCanvas(Rect dirty)就是锁住画布中的某个区域,绘画完成后也只更新这个区域的内容到屏幕。使用后一接口的初衷是只更新必要的画面内容以节省时间,提高程序运行的效率,适用于大动态画面的场景。

        然而,在实际使用lockCanvas(Rect dirty) 时却发现它似乎也是要更新完整个屏幕的,比如我在第一帧的时候画了整个画面,然后按下了某一按钮,于是在画第二帧时就只想更新那个按钮区域的图像,但结果却是这样子的:

        如图所示,在第2帧中,画了按钮的地方图像正常,而其它没有画的地方,还真的是什么也没画(黑的)……给人的感觉就是前面的图像没得到保留,在画第2帧之前系统会将画布清空,事实真的是这个样子的吗?这样说来 lockCanvas(Rect dirty) 接口又有何意义?

 

        上网搜索发现也有人在讨论这个问题,都讲得有点语焉不详,令我不得要领。后来发现多处提到了“双缓冲”机制,我突然灵光一现,细细想了一下便想通了其中的关节,并通过代码实践验证了自己的想法。

        Surface在更新画面的时候使用了双缓冲机制(关于双缓冲的作用就不再讨论了,这里只说明一下其工作过程,以下的部分叙述是为了方便说明问题,不具有严谨性),也就是在画布和屏幕之间建立了两块跟屏幕一样大小的内存区域,即缓冲区,如下图所示:

        在Surface刚建立起来的时候,它的两个缓冲区内存中是没有任何图像的,即都是全黑。

        1、在画第1帧前,我使用lockCanvas(null)接口,于是Surface锁住“缓冲区0”的全部区域,往画布上画的所有图片和文字,都被送到“缓冲区0”中。

        2、画完第1帧,使用 unlockCanvasAndPost()接口,则会将“缓冲区0”中所有的图像一股脑都送到屏幕中进行显示,画面显示正常。

        3、画第2帧前,使用lockCanvas(Rect dirty)接口,这时Surface锁住“缓冲区1”的部分区域,也就只能在这个区域中画上新的按钮图片。重点来了:这时候,“缓冲区1”中大部分区域都是没有图像的(黑色),除了绘画的按钮区域之外。

        4、画完第2帧,使用 unlockCanvasAndPost()接口,则会将“缓冲区1”中所有的图像显示到屏幕上。

        5、画第3帧,锁住“缓冲区0”……

        6、……

 

        整个过程如下图所示:

 

        由此可见,在Surface中画图像之前,画布中残留的不是前一帧的内容,而是前前帧的内容。因此,想要在单独画按钮的时候画面正常,那么必须先保证两个缓冲区都已经有背景画面,只要多 unlockCanvasAndPost()一次就可以了。

        下面给出简单的验证代码:

 

protectedvoid onDraw(Canvas canvas) {
    //绘制所有图像
}

publicvoid surfaceCreated(SurfaceHolder holder) {
    Canvas c;

    //画第1帧
    c = surfaceHolder.lockCanvas(null);
    onDraw(c);
    surfaceHolder.unlockCanvasAndPost(c);

    //画第2帧,内容和第1帧完全一样
    c = surfaceHolder.lockCanvas(null);
    onDraw(c);
    surfaceHolder.unlockCanvasAndPost(c);

    //画第3帧,单画按钮区域
    {
        float         img_x = 0, img_y = 0;
        Paint          paint = new Paint();
        Resources      res = getResources();
        Rect           rect;

        img_x = res.getDimension(R.dimen.btn_ok_x_1);
        img_y = res.getDimension(R.dimen.btn_ok_y);
        rect = new Rect((int)img_x, (int)img_y, (int)img_x + 50, (int)img_y + 50);
        c = surfaceHolder.lockCanvas(rect);
        c.drawBitmap(btn_ok, img_x, img_y + 10, paint);
        surfaceHolder.unlockCanvasAndPost(c);
    }  
}


  • 5
    点赞
  • 28
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值