android双缓冲绘图技术分析
来源:互联网 发布:安卓手机上的编程软件 编辑:程序博客网 时间:2024/05/21 09:20
双缓冲、多缓冲技术在计算机科学中其实是一个广义的概念,不过其本质上的意思都是差不多的。今天我们就来讲一讲双缓冲技术在android绘图中的应用。
何谓缓冲?
在理解双缓冲的原理之前,我们先要明白,什么叫缓冲?
我们可以举一个比较通俗的粟子,比如:
工头给你一个任务,让你把50块大板砖从A处搬到距离你1000米之外的B处去。你心想,50块板砖? 小case,我一次就能扛完。于是你撸起袖子,一步一步,真的一趟就搞定了。这个时候工头一声奸笑对你说,小伙子不错,那边还有2000块砖,你也搬过去吧。。。
看到这堆积如山的砖头,你眼前一黑,这孙子真是想累死我啊,钱给这么少还干这么多活!
可是没办法呀,谁叫自己当初书读得少,长大了只能靠搬砖为生呢。正当你准备徒手一趟一趟地开始干时,丰满漂亮的工头,的老婆来了,她走过来,带着迷一般的微笑。那种笑容,甜蜜优雅,仿佛春风拂过泸沽湖,秋雨浸润九寨沟,让你虎躯一震。她对你说,你开工地上的卡车把这些砖搬过去吧,2000块砖太多了,一趟一趟搬太累。
你瞬间来了精神,把砖搬到卡车上,油门一踩不带走一片云彩,一下就把2000块砖搬过去了。。。
............
“快起来,什么时候了还在睡,快去搬砖!”
该死的工头又来催!
缓冲的概念就讲到这里。
Android绘图中的双缓冲
我们知道,我们在绘图时有两样东西是少不了的,一个是Canvas(画布),一个是Paint(画笔)。Canvas提供画各种图形的方法,如画圆(drawCircle),画矩形(drawRect)等等,Paint用来设置画笔的样式,比如笔的粗细,颜色等。每个Canvas内部持有一个Bitmap对象的引用,画图的过程其实就是往这个Bitmap当中写入ARGB信息。
比如我们现在自定义一个View,在上面画一个矩形和一个圆:
@Override protected void onDraw(Canvas canvas) { canvas.drawRect(rect,mPaint); canvas.drawCircle(cx,cy,100,mPaint); }
那么现在有一个问题,画矩形和画圆是两个独立的动作,会不会在drawRect执行完之后屏幕上马上就会显示出来一个矩形呢?
为了验证我们的猜想,我们在两个绘图动作中加一个sleep:
@Override protected 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();}@Overrideprotected void onDraw(Canvas canvas) { canvas.drawBitmap(bufferBm,0,0,null);}
示意图:
双缓冲绘图的优缺点及适用场景
我们通过一个例子来说明。
实现这样一个功能,一个自定义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<>(); } @Override public 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; } @Override protected void onDraw(Canvas canvas) { for (Point p : mPoints) { canvas.drawCircle(p.x,p.y,50,mPaint); } }
在实验之前,我们先打开开发者选项里的”GPU呈现模式分析“,设置为“在屏幕上显示为条形图”(不同的手机可能有略微的差异,我这里用的是google Nexus5)。
可以看到,当画的圆数目比较少时,GPU的负荷较低,但是出现一个逐步上升的趋势:
内存使用情况是这样的:
当画的圆数目增加到比较大时,GPU负荷有点惨不妨睹了:
这时的内存使用情况:
我们现在改用双缓冲来绘图,代码如下:
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); } @Override public 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; } @Override protected void onDraw(Canvas canvas) { if (mBufferBitmap == null) { return; } canvas.drawBitmap(mBufferBitmap,0,0,null); }}
使用双缓冲,在数量较小时的GPU使用情况是这样的:
这时候的内存使用情况:
使用双缓冲,在数量非常大的时候,GPU使用情况是这样的:
内存使用情况:
从上面的实验数据我们可以得出结论:
- 在绘制数据量较小时,不使用双缓冲,GPU的负荷更低,即绘制性能更高;
- 在绘制数据量较大时,使用双缓冲绘图,绘制性能明显高于不使用双缓冲的情况;
- 使用双缓冲会增加内存消耗。
其实上面的结论也很好理解,就像上面举的搬砖的例子,如果砖少的话,用车来拉明显是划不来的,砖的数量很多的时候,用车来拉就可以节省很多时间,但是用车就要消耗额外的资源,这就需要根据不同的情况做出正确的选择。
android的双缓冲绘图技术就讲到这里,有不对的地方或大家有什么问题欢迎留言。
android实现画板功能源码
转载请说明出处:http://www.jianshu.com/p/efc0bebfd22e
- android双缓冲绘图技术分析
- android绘制知识--双缓冲绘图技术
- 双缓冲技术绘图
- 双缓冲技术绘图
- 双缓冲技术绘图
- 双缓冲技术绘图
- 双缓冲技术绘图
- 关于android双缓冲绘图的分析
- VC双缓冲技术绘图
- Android双缓冲技术分析总结
- android 绘图之双缓冲绘图
- Android SurfaceView双缓冲绘图
- Android SurfaceView双缓冲绘图
- Android 双缓冲绘图机制
- C#绘图双缓冲技术总结
- C#绘图双缓冲技术总结
- C#绘图双缓冲技术总结(转)
- VC 绘图,使用双缓冲技术实现
- 深入理解java虚拟机-内存分配与回收策略
- Windows7 Telnet Connection refused
- 左耳朵耗子:拖累开发团队效率的困局与解决之道
- 如何招聘高技能的IT人才
- 如何在CMD下运用管理员权限
- android双缓冲绘图技术分析
- 删除cell时 报错 Assertion failure in -[UITableView _endCellAnimationsWithContext:]
- LintCode 70 二叉树的层次遍历 II
- Android——ServiceGPS轨迹记录
- iOS打包后收不到推送信息
- Hibernate hql 定义,from 子句
- HTML5中FormData对象的使用
- Mongo数据库操作
- <meta>标签的作用