android双缓冲绘图技术分析
转载请说明出处:http://www.jianshu.com/p/efc0bebfd22e
双缓冲、多缓冲技术在计算机科学中其实是一个广义的概念,不过其本质上的意思都是差不多的。今天我们就来讲一讲双缓冲技术在android绘图中的应用。
何谓缓冲?
在理解双缓冲的原理之前,我们先要明白,什么叫缓冲?
我们可以举一个比较通俗的粟子,比如:
工头给你一个任务,让你把50块大板砖从A处搬到距离你1000米之外的B处去。你心想,50块板砖? 小case,我一次就能扛完。于是你撸起袖子,一步一步,真的一趟就搞定了。这个时候工头一声奸笑对你说,小伙子不错,那边还有2000块砖,你也搬过去吧。。。
看到这堆积如山的砖头,你眼前一黑,这孙子真是想累死我啊,钱给这么少还干这么多活!
可是没办法呀,谁叫自己当初书读得少,长大了只能靠搬砖为生呢。正当你准备徒手一趟一趟地开始干时,丰满漂亮的工头,的老婆来了,她走过来,带着迷一般的微笑。那种笑容,甜蜜优雅,仿佛春风拂过泸沽湖,秋雨浸润九寨沟,让你虎躯一震。她对你说,你开工地上的卡车把这些砖搬过去吧,2000块砖太多了,一趟一趟搬太累。
你瞬间来了精神,把砖搬到卡车上,油门一踩不带走一片云彩,一下就把2000块砖搬过去了。。。
…………
“快起来,什么时候了还在睡,快去搬砖!”
该死的工头又来催!
缓冲的概念就讲到这里。
Android绘图中的双缓冲
我们知道,我们在绘图时有两样东西是少不了的,一个是Canvas(画布),一个是Paint(画笔)。Canvas提供画各种图形的方法,如画圆(drawCircle),画矩形(drawRect)等等,Paint用来设置画笔的样式,比如笔的粗细,颜色等。每个Canvas内部持有一个Bitmap对象的引用,画图的过程其实就是往这个Bitmap当中写入ARGB信息。
比如我们现在自定义一个View,在上面画一个矩形和一个圆:
@Overrideprotected void onDraw(Canvas canvas) {canvas.drawRect(rect,mPaint);canvas.drawCircle(cx,cy,100,mPaint);}
那么现在有一个问题,画矩形和画圆是两个独立的动作,会不会在drawRect执行完之后屏幕上马上就会显示出来一个矩形呢?
为了验证我们的猜想,我们在两个绘图动作中加一个sleep:
@Overrideprotected void onDraw(Canvas canvas) {canvas.drawRect(rect,mPaint);try {TimeUnit.MILLISECONDS.sleep(2000);} catch (InterruptedException e) {e.printStackTrace();}canvas.drawCircle(cx,cy,100,mPaint);}
我们会看到,并不是先显示矩形再显示圆,而是两个几乎同时一起显示出来的。这就说明必须要等onDraw方法执行完成之后,才会把数据交给GPU去处理展示。这就是android绘图当中的第一道缓冲,即显示缓冲区。
而所谓的双缓冲,在android绘图中其实就是再创建一个Canvas和对应的Bitmap,然后在onDraw方法里默认的Canvas通过drawBitmap画刚才new的那个bitmap从而实现双缓冲。用代码简单的表述是这样的:
private void init(){Bitmap bufferBm = Bitmap.create(getWidth,getHeight,Bitmap.Config.ARGB_8888);Canvas bufferCanvas = new Canvas(bufferBm);
}private void drawSomething(){bufferCanvas.drawRect();bufferCanvas.drawCircle();...invalidate();
}@Override
protected void onDraw(Canvas canvas) {canvas.drawBitmap(bufferBm,0,0,null);
}
示意图:
![](http://upload-images.jianshu.io/upload_images/5082249-06395d0edf9fb658.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/438)
双缓冲绘图的优缺点及适用场景
我们通过一个例子来说明。
实现这样一个功能,一个自定义View,每次点击的时候在点击处画一个圆。我们先不使用双缓冲来实现:
不用双缓冲的代码:
public class MyView extends View{private Paint mPaint;private List<Point> mPoints;public MyView(Context context) {super(context);}public MyView(Context context, AttributeSet attrs) {super(context, attrs);mPaint = new Paint(Paint.ANTI_ALIAS_FLAG | Paint.DITHER_FLAG);mPaint.setStyle(Paint.Style.FILL);mPaint.setColor(Color.GREEN);setBackgroundColor(Color.WHITE);mPoints = new ArrayList<>();}@Overridepublic boolean onTouchEvent(MotionEvent event) {int action = event.getAction();switch (action){case MotionEvent.ACTION_DOWN:mPoints.add(new Point((int)event.getX(),(int)event.getY()));break;case MotionEvent.ACTION_UP:invalidate();break;}return true;}@Overrideprotected void onDraw(Canvas canvas) {for (Point p : mPoints) {canvas.drawCircle(p.x,p.y,50,mPaint);}}
在实验之前,我们先打开开发者选项里的”GPU呈现模式分析“,设置为“在屏幕上显示为条形图”(不同的手机可能有略微的差异,我这里用的是google Nexus5)。
可以看到,当画的圆数目比较少时,GPU的负荷较低,但是出现一个逐步上升的趋势:
![](http://upload-images.jianshu.io/upload_images/5082249-da6fd25dda8540d7.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/380)
内存使用情况是这样的:
![](http://upload-images.jianshu.io/upload_images/5082249-ed4b466ab9a50d0d.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/700)
当画的圆数目增加到比较大时,GPU负荷有点惨不妨睹了:
![](http://upload-images.jianshu.io/upload_images/5082249-6a96c333409350d4.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/377)
这时的内存使用情况:
![](http://upload-images.jianshu.io/upload_images/5082249-e7def5e0cd1cdba1.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/700)
我们现在改用双缓冲来绘图,代码如下:
public class MyView extends View{private Paint mPaint;private Canvas mBufferCanvas;private Bitmap mBufferBitmap;public MyView(Context context) {super(context);}public MyView(Context context, AttributeSet attrs) {super(context, attrs);mPaint = new Paint(Paint.ANTI_ALIAS_FLAG | Paint.DITHER_FLAG);mPaint.setStyle(Paint.Style.FILL);mPaint.setColor(Color.GREEN);setBackgroundColor(Color.WHITE);}@Overridepublic boolean onTouchEvent(MotionEvent event) {int action = event.getAction();switch (action){case MotionEvent.ACTION_DOWN:if (mBufferBitmap == null) {mBufferBitmap = Bitmap.createBitmap(getWidth(),getHeight(), Bitmap.Config.ARGB_8888);mBufferCanvas = new Canvas(mBufferBitmap);}mBufferCanvas.drawCircle((int)event.getX(),(int)event.getY(),50,mPaint);break;case MotionEvent.ACTION_UP:invalidate();break;}return true;}@Overrideprotected void onDraw(Canvas canvas) {if (mBufferBitmap == null) {return;}canvas.drawBitmap(mBufferBitmap,0,0,null);}
}
使用双缓冲,在数量较小时的GPU使用情况是这样的:
![](http://upload-images.jianshu.io/upload_images/5082249-8ec616aef42a7324.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/378)
这时候的内存使用情况:
![](http://upload-images.jianshu.io/upload_images/5082249-c444660e9e0d3c70.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/700)
使用双缓冲,在数量非常大的时候,GPU使用情况是这样的:
![](http://upload-images.jianshu.io/upload_images/5082249-7e19e3725aa2fbdc.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/382)
内存使用情况:
![](http://upload-images.jianshu.io/upload_images/5082249-46019c4c95e95758.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/700)
从上面的实验数据我们可以得出结论:
- 在绘制数据量较小时,不使用双缓冲,GPU的负荷更低,即绘制性能更高;
- 在绘制数据量较大时,使用双缓冲绘图,绘制性能明显高于不使用双缓冲的情况;
- 使用双缓冲会增加内存消耗。
其实上面的结论也很好理解,就像上面举的搬砖的例子,如果砖少的话,用车来拉明显是划不来的,砖的数量很多的时候,用车来拉就可以节省很多时间,但是用车就要消耗额外的资源,这就需要根据不同的情况做出正确的选择。
android的双缓冲绘图技术就讲到这里,有不对的地方或大家有什么问题欢迎留言。
android实现画板功能源码
![](http://upload-images.jianshu.io/upload_images/5082249-1003f419349f42de.gif?imageMogr2/auto-orient/strip%7CimageView2/2/w/320)
转载请说明出处:http://www.jianshu.com/p/efc0bebfd22e
</div>
android双缓冲绘图技术分析相关推荐
- MFC绘制动态曲线,用双缓冲绘图技术防闪烁
转载自:ZHY_ongu的博客:MFC绘制动态曲线,用双缓冲绘图技术防闪烁 先上效果图 随着时间的推移,曲线向右平移,同时X轴的时间坐标跟着更新. 一.如何绘制动态曲线. 所谓动画,都是一帧一帧 ...
- VC中的双缓冲绘图技术
之前在做图形绘制的时候,发现在拖动图形时候,会出现闪烁的情况,后来就上网找了一下双缓冲绘图,本文非原创,只是想保存下来,以后要用的时候不用再到处去搜,也希望能帮助有这方面困惑的朋友 原文来自http: ...
- [转载] MFC绘制动态曲线,用双缓冲绘图技术防闪烁
转载的原文地址 先上效果图 随着时间的推移,曲线向右平移,同时X轴的时间坐标跟着更新. 一.如何绘制动态曲线 所谓动画,都是一帧一帧的图像连续呈现在用户面前形成的.所以如果你掌握了如何绘制静态曲线,那 ...
- Qt之旅---10 双缓冲绘图
1 基本知识 但我们使用painter进行快速绘图时会看到类似图下 的情况 双缓冲绘图技术 的原理 用两个画布进行绘图,一个用于显示,一个用于绘制,也就是将图画之后再显示 就可以避免上面的情况. 2 ...
- 【Qt】2D绘图之双缓冲绘图
00. 目录 文章目录 00. 目录 01. 概述 02. 开发环境 03. 绘制矩形 04. 双缓冲绘图 05. 附录 01. 概述 所谓的双缓冲绘图的概念.双缓冲(double-buffers)绘 ...
- [Qt教程] 第18篇 2D绘图(八)双缓冲绘图
[Qt教程] 第18篇 2D绘图(八)双缓冲绘图 楼主 发表于 2013-5-2 22:07:23 | 查看: 789| 回复: 1 双缓冲绘图 版权声明 该文章原创于Qter开源社区(www.qt ...
- 【QT】QT从零入门教程(十三):QT画笔工具QPainter (双缓冲绘图)
QPainter 用于执行绘图操作,其提供的 API 在 GUI 或 QImage.QOpenGLPaintDevice.QWidget 和QPaintDevice 显示图形(线.形状.渐变等). ...
- c语言双缓冲怎么用,C语言游戏编程:GDI怎么实现双缓冲绘图去掉闪烁
在上篇文章中将我要用 C语言重新写一个俄罗斯方块 ,使用的是GDI的绘图模式(目前正在移植到DX上去,想添加一些更好友好的动画).数据与动画分离,动画的帧率保持在30左右.但是绘图的时候画面出现了强烈 ...
- Cimage下实现双缓冲绘图
双缓冲即在内存中创建一个与屏幕绘图区域一致的对象,先将图形绘制到内存中的这个对象上,再一次性将这个对象上的图形拷贝到屏幕上,这样能大大加快绘图的速度. 双缓冲绘图的步骤: 1.在内存中创建与画布一致的 ...
最新文章
- 网易有道词典笔 —— 73 岁“人类高质量”奶奶梅耶马斯克的中文学习之选
- 微信小程序底部导航Tabbar
- AI开发者大会之计算机视觉技术实践与应用:2020年7月3日《如何利用计算机视觉增加便利店连锁每日销售额》、《基于图像 / 视频的人脸和人体分析基础技术及其应用介绍》
- pandas.get_dummies
- 数据科学入门与实战:玩转pandas之五
- 你应该知道的 8 个Java 的领军人物
- 分享一个漂亮WPF界面框架创作过程及其源码
- 读书笔记--精通CSS高级Web标准解决方案(一)---CSS基础
- 自适应各终端懒人网址导航源码v1.6
- 三步教你免费下载省,市,区县行政区Shp数据
- 定时器 Cron表达式
- kindeditor编辑器一键保存远程图片
- 关于kali的pycharm创建快捷方式
- 新手配置Intel NUC8i5INH的Ubuntu 16.04 时无法上网
- pcf8591c语言编程,ADDA系列PCF8591的驱动程序
- 网络正常连接,浏览器无法打开网页的解决方法
- 2013 CocoaChina微信精选之技术汇
- 阿昆的Java学习日记Day2
- 简单远程遥控程序【网络程序设计 - 简单远程遥控程序,C实现】
- 金蝶K3 WISE 15.1金蝶K3 15.1金蝶K3 V15.1 金蝶K3 WISE 15.0金蝶K3 15.0金蝶K3 V15.0 14.3/14.2/14.1/14.0/13.1/13.0 12
热门文章
- 机器学习十大经典算法之朴素贝叶斯分类
- C++学习系列笔记(五)
- tinypng 批量处理插件_分享六款逆天的Excel插件,高效处理数据必备!低调使用...
- script链接标签前置无法读取的解决
- html做3d游戏进微波,射频微波电路设计.html(350页)-原创力文档
- android动画能超过父容器吗,Android中你不得不知道的动画知识 (一)
- python跳过错误_Pandas之read_csv()读取文件跳过报错行的解决
- puts遇到空格无法输出_ACM输出超限|puts与printf
- 虚拟机Oracle错误,解决xp虚拟机下oracle的几个错误
- 关于计算机网络的鼻祖是,笔记本的前世今生!谁才是笔记本的开山鼻祖?