网站做缓存,企业网站如何优化排名,动态设计网站,.net网站开发架构Android中的Surface和SurfaceView 转自#xff1a;http://technicalsearch.iteye.com/blog/1967616 一、什么是Surface 简单的说Surface对应了一块屏幕缓冲区#xff0c;每个window对应一个Surface#xff0c;任何View都要画在Surface的Canvas上#xff08;后面有原因解释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的源码 [java] view plain copy 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创建的时候都会创建一个MyWindownew 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就是模型的意思或者说是数据模型或者更简单地说就是数据也就是这里的SurfaceView即视图代表用户交互界面也就是这里的SurfaceViewSurfaceHolder很明显可以理解为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、创建一个绘制线程如下 [java] view plain copy 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类如下 [java] view plain copy 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代码使之如下 [java] view plain copy 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 viewsurfaceviewglsurfaceview的区别 答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来控制。