Surface、SurfaceView、SurfaceHolder及SurfaceHolder.Callback之间的关系

一、Surface

Surface就是“表面”的意思。在SDK的文档中,对Surface的描述是这样 的:“Handle onto a raw buffer that is being managed by the screen compositor”,翻译成中文就是“由屏幕显示内容合成器(screen compositor)所管理的原生缓冲器的句柄”,这句话包括下面两个意思:

1.      通过Surface(因为Surface是句柄)就可以获得原生缓冲器以及其中的内容。就像在C语言中,可以通过一个文件的句柄,就可以获得文件的内容一样;

2.      原生缓冲器(rawbuffer)是用于保存当前窗口的像素数据的。

引伸地,可以认为Android中的Surface就是一个用来画图形 (graphics)或图像(image)的地方。通常画图是在一个Canvas对象上面进行的,由此,可以推知一 个Surface对象中应该包含有一个Canvas对象,事实上的确如此,而且这一点可以很容易通过debug运行程序的方式得到证明(将光标停留在对象 变量surface上,会弹出一个对话框,其中红色方框的内容,就表面surface中有一个CompatileCanvas成员变量)当然,看源代码也 是可以证明这一点:

所以,Surface中的Canvas成员,是专门用于供程序员画图的场所,就像黑板一样;其中的原生缓冲器是用来保存数据的地方;Surface本身的作用类似一个句柄,得到了这个句柄就可以得到其中的Canvas、原生缓冲器以及其它方面的内容。

二、SurfaceView

通过SurfaceView就可以看到Surface的部分或者全部的内容:

SurfaceView是Android中View的子类。事实上,在Android中所有用于界面展示的类皆为View的子类,包括那些不可见的、各种各样的Layout。

在Android中Surface是从Object派生而来,且实现了 Parcelable接口。看到Parcelable就让人能很自然地想到数据容器,SurfaceView就是用来展示Surface中的数据的。在这 个层面上而言,Surface就是管理数据的地方,SurfaceView就是展示数据的地方。

三、SurfaceHolder

SurfaceHolder是一个接口,其作用就像一个关于Surface的监听器。 提供访问和控制Surface 相关的方法 ,它通过三个回调方法,让我们可以感知到Surface的创建、销毁或者改变。在SurfaceView中有一个方法 getHolder。

除下面将要提到的SurfaceHolder.Callback外,SurfaceHolder还提供了很多重要的方法,其中最重要的就是:

1.        abstract void addCallback(SurfaceHolder.Callback callback)

为SurfaceHolder添加一个SurfaceHolder.Callback回调接口。

2.        abstract Canvas lockCanvas()

获取一个Canvas对象,并锁定之。所得到的Canvas对象,其实就是Surface中一个成员。

3.        abstract Canvas lockCanvas(Rectdirty)

同上。但只锁定dirty所指定的矩形区域,因此效率更高。

4.        abstract void unlockCanvasAndPost(Canvascanvas)

当修改Surface中的数据完成后,释放同步锁,并提交改变,然后将新的数据进行展示,同时Surface中相关数据会被丢失。

5.      public abstract void setType (int type)

         设置Surface的类型,接收如下的参数:

SURFACE_TYPE_NORMAL:用RAM缓存原生数据的普通Surface

SURFACE_TYPE_HARDWARE:适用于DMA(Direct memory access )引擎和硬件加速的Surface

SURFACE_TYPE_GPU:适用于GPU加速的Surface

SURFACE_TYPE_PUSH_BUFFERS:表明该Surface不包含原 生数据,Surface用到的数据由其他对象提供,在Camera图像预览中就使用该类型的Surface,有Camera负责提供给预览Surface 数据,这样图像预览会比较流畅。如果设置这种类型则就不能调用lockCanvas来获取Canvas对象了。需要注意的是,在高版本的Android SDK中,setType这个方法已经被depreciated了。

2、3、4中的同步锁机制的目的,就是为了在绘制的过程中,Surface中的数据不会被改变。

从设计模式的高度来看,Surface、SurfaceView和 SurfaceHolder实质上就是广为人知的MVC,即Model-View-Controller。Model就是模型的意思,或者说是数据模型, 或者更简单地说就是数据,也就是这里的Surface;View即视图,代表用户交互界面,也就是这里的 SurfaceView;SurfaceHolder很明显可以理解为MVC中的Controller(控制器)。这样看起来三者之间的关系就清楚了很 多。

四、SurfaceHolder.Callback

前面已经讲到SurfaceHolder是一个接口,它通过回到方法的方式,让我们可 以感知到Surface的创建、销毁或者改变。其实这一点是通过其内部的静态子接口SurfaceHolder.Callback来实现的。 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对象在将要销毁前,该方法会被立即调用。

 

在Android SDK文档中,关于SurfaceView的描述里面,有一段这样的话:

这个类的目的之一,就是提供一个可以用另外一个线程(第二个线程)进行屏幕渲染的surface(译注:即UI线程和绘制线程可以分离)。如果你打算这样使用,那么应当注意一些线程方面的语义:

-           所有SurfaceView和 SurfaceHolder.Callback中声明的方法,必须在运行SurfaceView窗口中的线程中调用(典型地,就是应用的主线程。译注:即 UI线程),因为它们需要正确地将同时被绘制线程访问的各种状态进行同步。

-           必须保证,只有在背后的Surface有效的时候 – 在SurfaceHolder.Callback.surfaceCreated()和 SurfaceHolder.Callback.surfaceDestroyed()这两个方法调用之间,访问它。

 

下面,我们通过一个非常简单例子来实际感受一下(代码摘自http://www.cnblogs.com/xuling/archive/2011/06/06/android.html,并做了一些结构性的改动),请留意代码中的注释:

1.        在Eclipse中创建一个Android Project项目TestSurfaceView,并选择生成缺省的Activity TestSurfaceViewActivity

2.        创建一个绘制线程如下:

package com.pat.testsurfaceview;  
   
import android.graphics.Canvas;  
import android.graphics.Color;  
import android.graphics.Paint;  
import android.graphics.Rect;  
importandroid.view.SurfaceHolder;  
   
// 绘制线程  
public class MyThread extendsThread  
{  
         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);  
                                      
                                     // 创建画笔  
                                     Paintp = 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类如下:

package com.pat.testsurfaceview;  
   
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;  
          
         publicMySurfaceView(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(SurfaceHolderholder)  
         {  
                   // 结束线程。当这个方法调用时,说明Surface即将要被销毁了  
                   myThread.setRun(false);  
         }  
}

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

package com.pat.testsurfaceview;  
   
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));  
    }  
}

运行结果:

很显然,我们可以在MyThread的run方法中,做很多更有意思的事情。弄清楚了 Surface、SurfaceView、SurfaceHolder和SurfaceHolder.Callback这些概念,以及它们之间的关系,对 我们更好地使用它们应该会有相当大的帮助。

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值