Android中的Surface和SurfaceView

Posted Sharley

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Android中的Surface和SurfaceView相关的知识,希望对你有一定的参考价值。

一、什么是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的源码:

  1. <span style="font-size:14px;color:#333333;">   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);     
       }  </span>  

     

        很明显,每个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、创建一个绘制线程如下: 

 
  1. 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类如下: 

 
  1.  1 import android.content.Context;  
     2 import android.view.SurfaceHolder;  
     3 import android.view.SurfaceView;  
     4   
     5 public class MySurfaceView extends SurfaceView<span style="font-family:Arial;"> </span>implements<span style="font-family:Arial;">  </span>SurfaceHolder.Callback  
     6 {  
     7          private SurfaceHolder holder;  
     8          private MyThread myThread;  
     9           
    10          public  MySurfaceView(Context context)  
    11          {  
    12                    super(context);  
    13                     
    14                    // 通过SurfaceView获得SurfaceHolder对象  
    15                    holder = getHolder();  
    16                     
    17                    // 为holder添加回调结构SurfaceHolder.Callback  
    18                    holder.addCallback(this);  
    19                     
    20                    // 创建一个绘制线程,将holder对象作为参数传入,这样在绘制线程中就可以获得holder  
    21                    // 对象,进而在绘制线程中可以通过holder对象获得Canvas对象,并在Canvas上进行绘制  
    22                    myThread = new MyThread(holder);  
    23          }  
    24   
    25          // 实现SurfaceHolder.Callback接口中的三个方法,都是在主线程中调用,而不是在绘制线程中调用的  
    26          @Override  
    27          public void  surfaceChanged(SurfaceHolder holder, int format, int width, int height)  
    28          {  
    29          }  
    30   
    31          @Override  
    32          public void  surfaceCreated(SurfaceHolder holder)  
    33          {  
    34                    // 启动线程。当这个方法调用时,说明Surface已经有效了  
    35                    myThread.setRun(true);  
    36                    myThread.start();  
    37          }  
    38   
    39          @Override  
    40          public void surfaceDestroyed(SurfaceHolder holder)  
    41          {  
    42                    // 结束线程。当这个方法调用时,说明Surface即将要被销毁了  
    43                    myThread.setRun(false);  
    44          }  
    45 }  

     


        4、修改TestSurfaceViewActivity.java代码,使之如下:

 

      1import android.app.Activity;  

  1.  2 import android.os.Bundle;  
     3   
     4 public class TestSurfaceViewActivity extends Activity  
     5 {  
     6     @Override  
     7     public void onCreate(Bundle savedInstanceState)  
     8     {  
     9         super.onCreate(savedInstanceState);  
    10         //setContentView(R.layout.main);  
    11         setContentView(new MySurfaceView(this));  
    12     }  
    13 }  

     


运行结果:技术分享

 

 

原文:http://blog.csdn.net/tgww88/article/details/7973476

 

以上是关于Android中的Surface和SurfaceView的主要内容,如果未能解决你的问题,请参考以下文章

深入Android系统Android图形显示系统-1-显示原理与Surface

android中没有Surface View的媒体管道中的地标扣除

Android View显示流程

如何使用 Android 的“Surface”类?

了解 Canvas 和 Surface 概念

Android Surface理解