转自:http://technicalsearch.iteye.com/blog/1967616
一、什么是Surface
简单的说Surface对应了一块屏幕缓冲区,每个window对应一个Surface,任何View都要画在Surface的Canvas上(后面有原因解释)。传统的view共享一块屏幕缓冲区,所有的绘制必须在UI线程中进行。
在SDK的文档中,对Surface的描述是这样的:“Handle onto a raw buffer that is being managed by the screen compositor”,翻译成中文就是“由屏幕显示内容合成器(screen compositor)所管理的原始缓冲区的句柄”,这句话包括下面两个意思:
1、通过Surface(因为Surface是句柄)就可以获得原生缓冲器以及其中的内容。就像在C++语言中,可以通过一个文件的句柄,就可以获得文件的内容一样。
2、 原始缓冲区(a raw buffer)是用于保存当前窗口的像素数据的。
引伸地,可以认为Android中的Surface就是一个用来画图形(graphics)或图像(image)的地方。
根据Java方面的常规知识,我们知道通常画图是在一个Canvas对象上面进行的,由此,可以推知一个Surface对象中应该包含有一个Canvas(画布)对象。因此,在前面提及的两个意思的基础上,可以再加上一条:
3、Surface中有一个Canvas成员,专门用于画图的。
由以上的概括,我们总结如下:Surface中的Canvas成员,是专门用于供程序员画图的场所,就像黑板一样;其中的原始缓冲区是用来保存数据的地方;Surface本身的作用类似一个句柄,得到了这个句柄就可以得到其中的Canvas、原始缓冲区以及其它方面的内容。
Surface是用来管理数据的。(句柄)
二、什么是SurfaceView
说SurfaceView是一个View也许不够严谨,然而从定义中pubilc classSurfaceView extends View{.....}显示SurfaceView确实是派生自View,但是SurfaceView却有自己的Surface,请看SurfaceView的源码:
- if (mWindow == null) {
- mWindow = new MyWindow(this);
- mLayout.type = mWindowType;
- mLayout.gravity = Gravity.LEFT|Gravity.TOP;
- mSession.addWithoutInputChannel(mWindow, mWindow.mSeq, mLayout,
- mVisible ? VISIBLE : GONE, mContentInsets);
- }
很明显,每个SurfaceView创建的时候都会创建一个MyWindow,new MyWindow(this)中的this正是SurfaceView自身,因此将SurfaceView和window绑定在一起,由第一部分我们知道,一个window对应一个Surface,因此SurfaceView也就内嵌了一个自己的Surface,可以认为SurfaceView是用来控制Surface中View的位置和尺寸的。
SurfaceView就是展示Surface中数据的地方,同时可以认为SurfaceView是用来控制Surface中View的位置和尺寸的。
大家都知道,传统View及其派生类的更新只能在UI线程,然而UI线程还同时处理其他交互逻辑,这就无法保证View更新的速度和帧率了,而SurfaceView可以用独立的线程进行绘制,因此可以提供更高的帧率,例如游戏,摄像头取景等场景就比较适合SurfaceView来实现。
三、什么是SurfaceHolder
SurfaceHolder是一个接口,其作用就像一个关于Surface的监听器,提供访问和控制SurfaceView内嵌的Surface 相关的方法。它通过三个回调方法,让我们可以感知到Surface的创建、销毁或者改变。
在SurfaceView中有一个方法getHolder,可以很方便地获得SurfaceView内嵌的Surface所对应的监听器接口SurfaceHolder。
除下面将要提到的SurfaceHolder.Callback外,SurfaceHolder还提供了很多重要的方法,其中最重要的就是:
1、abstract void addCallback(SurfaceHolder.Callbackcallback):为SurfaceHolder添加一个SurfaceHolder.Callback回调接口。
2、abstract Canvas lockCanvas():获取一个Canvas对象,并锁定之。所得到的Canvas对象,其实就是Surface中一个成员。
3、abstract Canvas lockCanvas(Rect dirty):同上。但只锁定dirty所指定的矩形区域,因此效率更高。
4、abstract void unlockCanvasAndPost(Canvas canvas):当修改Surface中的数据完成后,释放同步锁,并提交改变,然后将新的数据进行展示,同时Surface中相关数据会被丢失。
2、3、4中的同步锁机制的目的,就是为了在绘制的过程中,Surface中的数据不会被改变。lockCanvas是为了防止同一时刻多个线程对同一canvas写入。
总结:从设计模式的高度来看,Surface、SurfaceView和SurfaceHolder实质上就是广为人知的MVC,即Model-View-Controller。Model就是模型的意思,或者说是数据模型,或者更简单地说就是数据,也就是这里的Surface;View即视图,代表用户交互界面,也就是这里的SurfaceView;SurfaceHolder很明显可以理解为MVC中的Controller(控制器)。
四、什么是SurfaceHolder.Callback
SurfaceHolder.Callback主要是当底层的Surface被创建、销毁或者改变时提供回调通知,由于绘制必须在Surface被创建后才能进行,因此SurfaceHolder.Callback中的surfaceCreated 和surfaceDestroyed 就成了绘图处理代码的边界。
SurfaceHolder.Callback中定义了三个接口方法:
1、abstract void surfaceChanged(SurfaceHolder holder, int format, int width, int height):当surface发生任何结构性的变化时(格式或者大小),该方法就会被立即调用。
2、abstract void surfaceCreated(SurfaceHolder holder):当surface对象创建后,该方法就会被立即调用。
3、abstract void surfaceDestroyed(SurfaceHolder holder):当surface对象在将要销毁前,该方法会被立即调用。
五、实例演示
下面,我们通过一个非常简单例子来实际感受一下,请留意代码中的注释:
1、在Eclipse中创建一个Android Project项目TestSurfaceView,并选择生成缺省的Activity TestSurfaceViewActivity
2、创建一个绘制线程如下:
- import android.graphics.Canvas;
- import android.graphics.Color;
- import android.graphics.Paint;
- import android.graphics.Rect;
- importandroid.view.SurfaceHolder;
- // 绘制线程
- public class MyThread extends Thread
- {
- private SurfaceHolder holder;
- private boolean run;
- public MyThread(SurfaceHolder holder)
- {
- this.holder = holder;
- run = true;
- }
- @Override
- public void run()
- {
- int counter = 0;
- Canvas canvas = null;
- while(run)
- {
- // 具体绘制工作
- try
- {
- // 获取Canvas对象,并锁定之
- canvas= holder.lockCanvas();
- // 设定Canvas对象的背景颜色
- canvas.drawColor(Color.WHITE);
- // 创建画笔
- Paint p = new Paint();
- // 设置画笔颜色
- p.setColor(Color.BLACK);
- // 设置文字大小
- p.setTextSize(30);
- // 创建一个Rect对象rect
- Rect rect = new Rect(100, 50, 380, 330);
- // 在canvas上绘制rect
- canvas.drawRect(rect,p);
- // 在canvas上显示时间
- canvas.drawText("Interval = " + (counter++) + " seconds.", 100, 410, p);
- Thread.sleep(1000);
- }
- catch(Exception e)
- {
- e.printStackTrace();
- }
- finally
- {
- if(canvas != null)
- {
- // 解除锁定,并提交修改内容
- holder.unlockCanvasAndPost(canvas);
- }
- }
- }
- }
- public boolean isRun()
- {
- return run;
- }
- public void setRun(boolean run)
- {
- this.run = run;
- }
- }
3、自定义一个SurfaceView类如下:
- import android.content.Context;
- import android.view.SurfaceHolder;
- import android.view.SurfaceView;
- public class MySurfaceView extends SurfaceView implements SurfaceHolder.Callback
- {
- private SurfaceHolder holder;
- private MyThread myThread;
- public MySurfaceView(Context context)
- {
- super(context);
- // 通过SurfaceView获得SurfaceHolder对象
- holder = getHolder();
- // 为holder添加回调结构SurfaceHolder.Callback
- holder.addCallback(this);
- // 创建一个绘制线程,将holder对象作为参数传入,这样在绘制线程中就可以获得holder
- // 对象,进而在绘制线程中可以通过holder对象获得Canvas对象,并在Canvas上进行绘制
- myThread = new MyThread(holder);
- }
- // 实现SurfaceHolder.Callback接口中的三个方法,都是在主线程中调用,而不是在绘制线程中调用的
- @Override
- public void surfaceChanged(SurfaceHolder holder, int format, int width, int height)
- {
- }
- @Override
- public void surfaceCreated(SurfaceHolder holder)
- {
- // 启动线程。当这个方法调用时,说明Surface已经有效了
- myThread.setRun(true);
- myThread.start();
- }
- @Override
- public void surfaceDestroyed(SurfaceHolder holder)
- {
- // 结束线程。当这个方法调用时,说明Surface即将要被销毁了
- myThread.setRun(false);
- }
- }
4、修改TestSurfaceViewActivity.java代码,使之如下:
- import android.app.Activity;
- import android.os.Bundle;
- public class TestSurfaceViewActivity extends Activity
- {
- @Override
- public void onCreate(Bundle savedInstanceState)
- {
- super.onCreate(savedInstanceState);
- //setContentView(R.layout.main);
- setContentView(new MySurfaceView(this));
- }
- }
运行结果:
android view,surfaceview,glsurfaceview的区别:
答:SurfaceView是从View基类中派生出来的显示类,直接子类有GLSurfaceView和VideoView,可以看出GL和视频播放以及Camera摄像头一般均使用SurfaceView
SurfaceView和View最本质的区别在于,surfaceView是在一个新起的单独线程中可以重新绘制画面而View必须在UI的主线程中更新画面。
那么在UI的主线程中更新画面 可能会引发问题,比如你更新画面的时间过长,那么你的主UI线程会被你正在画的函数阻塞。那么将无法响应按键,触屏等消息。
当使用surfaceView 由于是在新的线程中更新画面所以不会阻塞你的UI主线程。但这也带来了另外一个问题,就是事件同步。比如你触屏了一下,你需要surfaceView中thread处理,一般就需要有一个event queue的设计来保存touch event,这会稍稍复杂一点,因为涉及到线程同步。
所以基于以上,根据游戏特点,一般分成两类。
1)被动更新画面的。比如棋类,这种用view就好了。因为画面的更新是依赖于 onTouch 来更新,可以直接使用 invalidate。 因为这种情况下,这一次Touch和下一次的Touch需要的时间比较长些,不会产生影响。
2)主动更新。比如一个人在一直跑动。这就需要一个单独的thread不停的重绘人的状态,避免阻塞main UI thread。所以显然view不合适,需要surfaceView来控制。
相关推荐
内容概要:本文介绍了一款基于MATLAB GUI的学生成绩管理系统,旨在提升学校教学管理的效率和准确性。系统主要由三个模块组成:考试收录数据模块、考试数据分析模块和统计分析数据模块。它不仅支持成绩的录入、显示、排序、查找,还包括特征值分析、直方图绘制和教师评语录入等功能。通过对成绩数据的综合分析,系统能为学校教学管理提供客观科学的数据支持。 适合人群:教育工作者(如教师、管理人员)和技术爱好者(特别是对MATLAB GUI感兴趣的开发者)。 使用场景及目标:适用于各类学校和教育机构,用于管理和分析学生成绩,帮助教师和管理者更好地了解学生的学习状况,改进教学质量。 阅读建议:对于希望深入了解如何利用MATLAB GUI进行学生成绩管理的读者来说,本文提供了详细的系统设计思路和功能实现方法,值得仔细研读并尝试实践。
内容概要:本文介绍了基于T-Mats库的涡扇发动机气路故障仿真模型,涵盖了多种类型的故障植入(如部件流量、效率及压比故障),并允许自定义故障程序和组合。该模型通过对软阈值去噪处理后的信号序列进行分析,提取真实的运行扰动信息,确保输出数据符合CMAPASS的排列要求。此外,该模型能够模拟航空发动机的典型气路故障,帮助研发和技术人员更准确地预测和评估发动机性能,从而提前采取预防措施。 适合人群:航空航天领域的研发人员、技术人员以及对航空发动机故障仿真感兴趣的学者。 使用场景及目标:①用于研究和开发涡扇发动机的气路故障诊断系统;②辅助工程师进行故障预测和性能评估;③为后续数据分析和实验验证提供可靠的数据基础。 其他说明:该模型不仅提高了仿真的准确性,还增强了对发动机运行状态的理解,为提升发动机性能和可靠性提供了强有力的技术支持。
scratch少儿编程逻辑思维游戏源码-scratch冒险.zip
少儿编程scratch项目源代码文件案例素材-爬塔.zip
内容概要:本文详细探讨了合金凝固模型中的相场模拟方法及其在各向异性枝晶生长研究中的应用。首先介绍了合金凝固模型的基本概念及其在现代制造业中的重要性,特别是在激光增材制造、选择性激光熔融和定向凝固技术中的应用。接着,重点讨论了相场模拟作为一种数值模拟方法,在预测合金凝固过程中组织结构演变方面的关键作用。文中还提供了MATLAB实现合金各向异性枝晶生长的具体代码及详细注释,以及Comsol用于偏微分方程求解的雪花生长模型。最后,文章总结了当前的研究进展,并展望了未来的发展趋势。 适合人群:从事材料科学、冶金工程、激光增材制造领域的研究人员和技术人员,尤其是对相场模拟和合金凝固感兴趣的学者。 使用场景及目标:适用于希望深入了解合金凝固过程、相场模拟方法及其在现代制造技术中应用的专业人士。目标是提高对合金凝固机制的理解,优化制造工艺,提升产品质量。 其他说明:文章不仅提供了理论分析,还包括具体的代码实现和详细的文献参考资料,有助于读者全面掌握相关技术和最新研究进展。
少儿编程scratch项目源代码文件案例素材-史莱姆出击.zip
少儿编程scratch项目源代码文件案例素材-忍者酷跑.zip
scratch少儿编程逻辑思维游戏源码-点击灌篮.zip
内容概要:本文介绍了将基于RBF神经网络的PID控制器应用于永磁同步电机(PMSM)转速环控制的方法及其性能优势。传统的PID控制器在面对非线性和时变系统时存在参数整定困难的问题,而引入RBF神经网络可以实现实时在线调参,提高系统的灵活性和鲁棒性。文中详细描述了Simulink模型的设计,特别是Matlab s-function模块中RBF神经网络的具体实现,包括高斯函数激活和带惯性的权值更新机制。实验结果显示,在转速突变情况下,改进后的控制器能够迅速稳定系统,超调量控制在2%以内,调节时间较传统方法缩短约40%,并且在负载变化时表现出色,无需重新整定参数。 适合人群:从事电机控制系统研究和开发的技术人员,尤其是对PID控制器优化感兴趣的工程师。 使用场景及目标:适用于需要提升PMSM转速环控制精度和响应速度的应用场合,如工业自动化设备、机器人等领域。目标是通过引入智能算法解决传统PID控制器参数整定难题,提高系统性能。 阅读建议:关注RBF神经网络与PID控制器结合的具体实现细节,特别是在Matlab s-function模块中的编码技巧以及参数调整策略。同时,注意学习率的选择和动量项的作用,这对于实际应用至关重要。
scratch少儿编程逻辑思维游戏源码-Scratch 奔跑.zip
内容概要:本文详细介绍了基于COMSOL有限元软件的变压器辐射传热数值分析方法。首先,解释了变压器内外辐射传热的基本机理,包括热量通过传导、对流和辐射的方式传递,重点在于辐射传热的作用及其数学描述。接着,逐步引导读者从零开始构建有限元仿真模型,涵盖模型参数确定、网格划分、材料属性定义、边界条件设置、传热方程设定、仿真运行及结果分析等多个步骤。最后,探讨了进一步研究的方向,如不同因素(温度、材料属性、几何形状)对辐射传热的影响,以及该模型在电力电子设备和热管理系统的潜在应用。 适合人群:电气工程专业学生、初学者和技术爱好者,尤其是对有限元仿真和变压器辐射传热感兴趣的群体。 使用场景及目标:适用于希望通过实际操作掌握有限元仿真技能的人群,旨在帮助他们理解变压器辐射传热机制并能独立完成相关仿真项目。 其他说明:本文不仅提供了理论知识,还附带了详细的视频教程和仿真模型,使学习过程更加直观易懂。
内容概要:本文详细介绍了交错并联Boost PFC(功率因数校正)仿真电路模型的设计与实现,特别是在临界BCM模式下的双闭环控制特性。文章首先解释了该电路的经典结构及其优势,即能够有效降低开关损耗和电流纹波。接着,重点讨论了双闭环控制的具体实现方法,包括外环电压控制和内环电流控制的MATLAB/Simulink代码示例。文中还特别强调了电流环中零交叉检测的重要性以及交错并联结构中驱动信号相位差的精确设置。此外,作者分享了将模型从Simulink转换到Plecs和Psim时遇到的问题及解决方案,如更换为带反向恢复特性的二极管模型和重新校准控制环路的采样周期。最后,文章展示了优化后的电流波形图,验证了所提方法的有效性。 适合人群:电力电子工程师、电源设计师、从事电力系统仿真的研究人员和技术爱好者。 使用场景及目标:适用于需要进行高效电源设计的研究和开发项目,旨在提高电源系统的性能,减少谐波失真,提升功率因数校正效果。 其他说明:文中提供的具体代码片段和参数设置有助于读者更好地理解和复现实验结果。同时,对于希望深入理解双闭环控制系统和BCM模式的人来说,本文提供了宝贵的实践经验。
scratch少儿编程逻辑思维游戏源码-3000 横版闯过.zip
内容概要:本文介绍了如何利用Matlab/Simulink构建空气涡轮发动机的动态仿真模型。首先,文章详细阐述了各个部件级模型的设计,包括进气道、涡轮、气室、压气机、尾喷管、转子动力学模块和容积模块。接着,重点讨论了PID控制器在维持发动机转速恒定方面的作用,尤其是在面对输出扭矩阶跃扰动时的表现。最后,提供了简单的Simulink模型代码片段,展示了如何设置和运行仿真模型,以便实时监控和调整发动机性能。 适合人群:航空航天工程领域的研究人员和技术人员,尤其是那些对空气涡轮发动机仿真感兴趣的读者。 使用场景及目标:适用于希望通过Matlab/Simulink进行空气涡轮发动机仿真研究的专业人士。主要目标是掌握空气涡轮发动机各部件的工作原理及其相互关系,同时学会使用PID控制器优化发动机性能。 其他说明:本文不仅提供了理论知识,还附有实际操作步骤和代码示例,帮助读者更好地理解和应用所学内容。
少儿编程scratch项目源代码文件案例素材-收集能量.zip
scratch少儿编程逻辑思维游戏源码-弹回的球.zip
少儿编程scratch项目源代码文件案例素材-铅笔画.zip
Sage Decrypter.zip
scratch少儿编程逻辑思维游戏源码-躲避火箭.zip
KEPServerEX6-6.17.269.0,最新版