zoukankan      html  css  js  c++  java
  • Android中的Android中的Surface和SurfaceView

     
     
    一、什么是Surface

              简单的说Surface对应了一块屏幕缓冲区,每个window对应一个Surface,任何View都要画在Surface上。传统的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="COLOR: #333333; FONT-SIZE: 14px">   if (mWindow == null) {  
    2.           mWindow = new MyWindow(this);  
    3.           mLayout.type = mWindowType;  
    4.           mLayout.gravity = Gravity.LEFT|Gravity.TOP;  
    5.           mSession.addWithoutInputChannel(mWindow, mWindow.mSeq, mLayout,  
    6.           mVisible ? VISIBLE : GONE, mContentInsets);   
    7.     }  </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 CanvaslockCanvas():获取一个Canvas对象,并锁定之。所得到的Canvas对象,其实就是Surface中一个成员。
           3、abstract CanvaslockCanvas(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;
    2. import android.graphics.Color;
    3. import android.graphics.Paint;
    4. import android.graphics.Rect;
    5. importandroid.view.SurfaceHolder;
    6. // 绘制线程
    7. public class MyThread extends Thread
    8. {
    9.          private SurfaceHolder holder;
    10.          private boolean run;
    11.         
    12.          public &nbsp;MyThread(SurfaceHolder holder)
    13.          {
    14.                    this.holder = holder;
    15.                    run = true;
    16.          }
    17.          @Override
    18.          public void run()
    19.          {
    20.                    int counter = 0;
    21.                    Canvas canvas = null;
    22.                    while(run)
    23.                    {
    24.                             // 具体绘制工作
    25.                             try
    26.                             {
    27.                                      // 获取Canvas对象,并锁定之
    28.                                      canvas= holder.lockCanvas();
    29.                                     
    30.                                      // 设定Canvas对象的背景颜色
    31.                                      canvas.drawColor(Color.WHITE);
    32.                                     
    33.                                      // 创建画笔
    34.                                      Paint p = new Paint();
    35.                                      // 设置画笔颜色
    36.                                      p.setColor(Color.BLACK);
    37.                                      // 设置文字大小
    38.                                      p.setTextSize(30);
    39.                                     
    40.                                      // 创建一个Rect对象rect
    41.                                      Rect &nbsp;rect = new Rect(100, 50, 380, 330);
    42.                                      // 在canvas上绘制rect
    43.                                      canvas.drawRect(rect,p);
    44.                                      // 在canvas上显示时间
    45.                                      canvas.drawText("Interval = " + (counter++) + " seconds.", 100, 410, p);
    46.                                      Thread.sleep(1000);
    47.                             }
    48.                             catch(Exception e)
    49.                             {
    50.                                      e.printStackTrace();
    51.                             }
    52.                             finally
    53.                             {
    54.                                      if(canvas != null)
    55.                                      {
    56.                                                // 解除锁定,并提交修改内容
    57.                                                holder.unlockCanvasAndPost(canvas);
    58.                                      }
    59.                             }
    60.                    }
    61.          }
    62.          public boolean isRun()
    63.          {
    64.                    return run;
    65.          }
    66.         
    67.          public void setRun(boolean run)
    68.          {
    69.                    this.run = run;
    70.          }
    71. }
    复制代码
    3、自定义一个SurfaceView类如下:
    1. import android.content.Context;
    2. import android.view.SurfaceHolder;
    3. import android.view.SurfaceView;
    4. public class MySurfaceView extends SurfaceView<SPAN style="FONT-FAMILY: Arial"> </SPAN>implements<SPAN style="FONT-FAMILY: Arial"> &nbsp;</SPAN>SurfaceHolder.Callback
    5. {
    6.          private SurfaceHolder holder;
    7.          private MyThread myThread;
    8.         
    9.          public &nbsp;MySurfaceView(Context context)
    10.          {
    11.                    super(context);
    12.                   
    13.                    // 通过SurfaceView获得SurfaceHolder对象
    14.                    holder = getHolder();
    15.                   
    16.                    // 为holder添加回调结构SurfaceHolder.Callback
    17.                    holder.addCallback(this);
    18.                   
    19.                    // 创建一个绘制线程,将holder对象作为参数传入,这样在绘制线程中就可以获得holder
    20.                    // 对象,进而在绘制线程中可以通过holder对象获得Canvas对象,并在Canvas上进行绘制
    21.                    myThread = new MyThread(holder);
    22.          }
    23.          // 实现SurfaceHolder.Callback接口中的三个方法,都是在主线程中调用,而不是在绘制线程中调用的
    24.          @Override
    25.          public void &nbsp;surfaceChanged(SurfaceHolder holder, int format, int width, int height)
    26.          {
    27.          }
    28.          @Override
    29.          public void &nbsp;surfaceCreated(SurfaceHolder holder)
    30.          {
    31.                    // 启动线程。当这个方法调用时,说明Surface已经有效了
    32.                    myThread.setRun(true);
    33.                    myThread.start();
    34.          }
    35.          @Override
    36.          public void surfaceDestroyed(SurfaceHolder holder)
    37.          {
    38.                    // 结束线程。当这个方法调用时,说明Surface即将要被销毁了
    39.                    myThread.setRun(false);
    40.          }
    41. }
    复制代码
    4、修改TestSurfaceViewActivity.java代码,使之如下:
    1. import android.app.Activity;
    2. import android.os.Bundle;[/font]
    3. [font=Arial]public class TestSurfaceViewActivity extends Activity
    4. {
    5.     @Override
    6.     public void onCreate(Bundle savedInstanceState)
    7.     {
    8.         super.onCreate(savedInstanceState);
    9.         //setContentView(R.layout.main);
    10.         setContentView(new MySurfaceView(this));
    11.     }
    12. }
    复制代码
    效果图:

    1347507375_2588.png

     
  • 相关阅读:
    $().each和$("input[name='XXX']")
    常规JS操作
    日期大小比较JS方法
    集合迭代
    技术点1
    GItHub pages 的使用方法
    node.js是做什么的?
    jQuery基础:下(事件及动画效果)
    jQuery基础:上(样式及DOM操作)
    页码demo制作
  • 原文地址:https://www.cnblogs.com/firecode/p/2755184.html
Copyright © 2011-2022 走看看