Android开发之SurfaceView

Android开发之SurfaceView

/*

* Android开发之SurfaceView

* 北京Android俱乐部群:167839253

* Created on: 2011-8-26

* Author: blueeagle

* Email: liujiaxiang@gmail.com

*/

在前面学习视频播放和简单照相机的制作的时候,用到了SurfaceView这个类。那么这个类是干什么的呢?如果不用这个类,用View类行不行呢?这个看起来是不行的。

如果做游戏或者视频相关开发的时候,将会用到SurfaceView。对于SurfaceView,首先需要了解一下它自己的位置:

extends View

java.lang.Object

android.view.View

android.view.SurfaceView

由手册可知:

SurfaceView是View类的继承类,这个View里内嵌了一个专门用于绘制的Surface,这个可以类似的理解成为一个在View里的Canvas。你可以控制这个Surface的格式和尺寸。Surfaceview类则控制这个Surface在屏幕上的正确位置。

《Android高级编程》里这样说:

在一般情况下,应用程序的View都是在相同的GUI线程中绘制的。这个主应用程序线程同时也用来处理所有的用户交互(例如按钮单击或者文本输入)。

对于一个View的onDraw()方法,不能够满足将其移动到后台线程中去。因为从后台线程修改一个GUI元素会被显式地禁止的。

当需要快速地更新View的UI,或者当前渲染代码阻塞GUI线程的时间过长的时候,SurfaceView就是解决上述问题的最佳选择。SurfaceView封装了一个Surface对象,而不是Canvas。这一点很重要,因为Surface可以使用后台线程绘制。对于那些资源敏感的操作,或者那些要求快速更新或者高速帧率的地方,例如使用3D图形,创建游戏,或者实时预览摄像头,这一点特别有用。

1. 何时应该使用SurfaceView

SurfaceView使用的方式与任何View所派生的类都是完全相同的。可以像其他View那样应用动画,并把它们放到布局中。

SurfaceView封装的Surface支持所有标准的Canvas方法进行绘图,同时也支持完全的OpenGL ES 库。

使用OpenGL,你可以在Surface上绘制任何支持2D或者3D对象,与在2D画布上模拟相同的效果相比,这种方法可以依靠硬件加速(可用的时候)来极大地提高性能。

对于显示动态的3D图像来说,例如,那些使用Google Earth 功能的应用程序,或者那些提供沉浸体验的交互式游戏,Surface特别有用。它还是实时显示摄像头预览的最佳选择。

2. 创建一个新的SurfaceView控件

创建一个新的SurfaceView控件需要创建一个新的扩展了SurfaceView的类,并实现SurfaceHolder.Callback。

SurfaceHolder回调可以在底层的Surface被创建和销毁的时候通知View,并传递给它SurfaceHolder对象的引用,其中包含了当前有效的Surface。

一个典型的SurfaceView 设计模型包括一个由Thread所派生的类,它可以接收对当前的SurfaceHolder的引用,并独立地更新它。

3. 使用SurfaceView创建3D控件

Android完全支持OpenGL ES 3D 渲染框架,其中包含了对设备的硬件加速的支持。SurfaceView控件提供了一个表面,可以在它上面渲染你的OpenGL场景。

那么我们在使用的时候可以这样使用:

被动更新画面的。比如棋类,这种用view就好了。因为画面的更新是依赖于 onTouch 来更新,可以直接使用 invalidate。 因为这种情况下,这一次Touch和下一次的Touch需要的时间比较长些,不会产生影响。

主动更新。比如一个人在一直跑动。这就需要一个单独的thread不停的重绘人的状态,避免阻塞main UI thread。所以显然view不合适,需要surfaceView来控制。

可以直接从内存或硬件设备比如相机等取得图像数据,是个非常重要的绘图容器。

它的特性是:可以在主线程之外的线程中向屏幕绘图。这样可以避免画图任务繁重的时候造成主线程阻塞,从而提高了程序的反应速度。

如何去使用一个SurfaceView:

首先继承SurfaceView并实现SurfaceHolder.Callback接口。因为使用SurfaceView 有一个原则,所有的绘图工作必须得在Surface 被创建之后才能开始。可以被直接复制到显存从而显示出来,这使得显示速度会非常快,而在Surface 被销毁之前必须结束。所以Callback 中的surfaceCreated 和surfaceDestroyed 就成了绘图处理代码的边界。

需要重写的方法

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

//在surface的大小发生改变时激发

(2)public void surfaceCreated(SurfaceHolder holder){}

//在创建时激发,一般在这里调用画图的线程。

(3)public void surfaceDestroyed(SurfaceHolder holder) {}

//销毁时激发,一般在这里将画图的线程停止、释放。

整个过程:继承SurfaceView并实现SurfaceHolder.Callback接口 ----> SurfaceView.getHolder()获得SurfaceHolder对象 ---->SurfaceHolder.addCallback(callback)添加回调函数---->SurfaceHolder.lockCanvas()获得Canvas对象并锁定画布----> Canvas绘画 ---->SurfaceHolder.unlockCanvasAndPost(Canvas canvas)结束锁定画图,并提交改变,将图形显示。

关于SurfaceHolder:

这里用到了一个类SurfaceHolder,可以把它当成surface的控制器,用来操纵surface。处理它的Canvas上画的效果和动画,控制表面,大小,像素等。
几个需要注意的方法:
(1)、abstract void addCallback(SurfaceHolder.Callback callback);
// 给SurfaceView当前的持有者一个回调对象。
(2)、abstract Canvas lockCanvas();
// 锁定画布,一般在锁定后就可以通过其返回的画布对象Canvas,在其上面画图等操作了。
(3)、abstract Canvas lockCanvas(Rect dirty);
// 锁定画布的某个区域进行画图等..因为画完图后,会调用下面的unlockCanvasAndPost来改变显示内容。
// 相对部分内存要求比较高的游戏来说,可以不用重画dirty外的其它区域的像素,可以提高速度。
(4)、abstract void unlockCanvasAndPost(Canvas canvas);
// 结束锁定画图,并提交改变。

测试代码如下:

  1. /*
  2. *Android开发之SurfaceView
  3. *SurfaceView01.java
  4. *Createdon:2011-8-25
  5. *Author:blueeagle
  6. *Email:liujiaxiang@gmail.com
  7. */
  8. packagecom.blueeagle;
  9. importandroid.app.Activity;
  10. importandroid.content.Context;
  11. importandroid.graphics.Canvas;
  12. importandroid.graphics.Color;
  13. importandroid.graphics.Paint;
  14. importandroid.graphics.Rect;
  15. importandroid.os.Bundle;
  16. importandroid.view.SurfaceHolder;
  17. importandroid.view.SurfaceView;
  18. publicclassSurfaceView01extendsActivity{
  19. /**Calledwhentheactivityisfirstcreated.*/
  20. @Override
  21. publicvoidonCreate(BundlesavedInstanceState){
  22. super.onCreate(savedInstanceState);
  23. setContentView(newMyView(this));
  24. }
  25. //视图内部类
  26. classMyViewextendsSurfaceViewimplementsSurfaceHolder.Callback
  27. {
  28. privateSurfaceHolderholder;
  29. privateMyThreadmyThread;
  30. publicMyView(Contextcontext){
  31. super(context);
  32. //TODOAuto-generatedconstructorstub
  33. holder=this.getHolder();
  34. holder.addCallback(this);
  35. myThread=newMyThread(holder);//创建一个绘图线程
  36. }
  37. @Override
  38. publicvoidsurfaceChanged(SurfaceHolderholder,intformat,intwidth,
  39. intheight){
  40. //TODOAuto-generatedmethodstub
  41. }
  42. @Override
  43. publicvoidsurfaceCreated(SurfaceHolderholder){
  44. //TODOAuto-generatedmethodstub
  45. myThread.isRun=true;
  46. myThread.start();
  47. }
  48. @Override
  49. publicvoidsurfaceDestroyed(SurfaceHolderholder){
  50. //TODOAuto-generatedmethodstub
  51. myThread.isRun=false;
  52. }
  53. }
  54. //线程内部类
  55. classMyThreadextendsThread
  56. {
  57. privateSurfaceHolderholder;
  58. publicbooleanisRun;
  59. publicMyThread(SurfaceHolderholder)
  60. {
  61. this.holder=holder;
  62. isRun=true;
  63. }
  64. @Override
  65. publicvoidrun()
  66. {
  67. intcount=0;
  68. while(isRun)
  69. {
  70. Canvasc=null;
  71. try
  72. {
  73. synchronized(holder)
  74. {
  75. c=holder.lockCanvas();//锁定画布,一般在锁定后就可以通过其返回的画布对象Canvas,在其上面画图等操作了。
  76. c.drawColor(Color.BLACK);//设置画布背景颜色
  77. Paintp=newPaint();//创建画笔
  78. p.setColor(Color.WHITE);
  79. Rectr=newRect(100,50,300,250);
  80. c.drawRect(r,p);
  81. c.drawText("这是第"+(count++)+"秒",100,310,p);
  82. Thread.sleep(1000);//睡眠时间为1秒
  83. }
  84. }
  85. catch(Exceptione){
  86. //TODO:handleexception
  87. e.printStackTrace();
  88. }
  89. finally
  90. {
  91. if(c!=null)
  92. {
  93. holder.unlockCanvasAndPost(c);//结束锁定画图,并提交改变。
  94. }
  95. }
  96. }
  97. }
  98. }
  99. }

转:http://blog.youkuaiyun.com/redoffice/article/details/6722067


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值