一、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)的地方。根据Java方面的常规知识,我们知道通常画图是在一个Canvas对象上面进行的,由此,可以推知一个Surface对象中应该包含有一个Canvas对象,事实上的确如此,而且这一点可以很容易通过debug运行程序的方式得到证明(将光标停留在对象变量surface上,会弹出一个对话框,其中红色方框的内容,就表面surface中有一个CompatileCanvas成员变量)当然,看源代码也是可以证明这一点:

因此,在前面提及的两个意思的基础上,可以再加上一条:

3.      Surface中有一个Canvas成员,专门用于画图的。

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

二、SurfaceView

SurfaceView,顾名思义就是Surface的View,通过SurfaceView就可以看到Surface的部分或者全部的内容,下面用一个图来形象地描述一下Surface和SurfaceView的关系:

也就是说,Surface是用通过SurfaceView才能展示其中的内容。从这个意思上来说,SurfaceView中的View之确切的含义应该是viewport即“视口”的意思,做过数据库设计的朋友知道,假定一个数据表有20个字段,但 我们常常只用到其中的5个字段,那么就可以在原数据表的基础上,通过SQL语句CREATEVIEW来创建只包含那5个字段内容的view。

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

所以说,SurfaceView中的View有两个含义:

1.      视口(viewport)的意思

2.      SurfaceView是View的派生类

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

三、SurfaceHolder

SurfaceHolder是一个接口,其作用就像一个关于Surface的监听器。提供访问和控制SurfaceView背后的Surface 相关的方法 (providingaccess and control over this SurfaceView's underlying 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(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(SurfaceHolderholder, int format, int width, int height)

当surface发生任何结构性的变化时(格式或者大小),该方法就会被立即调用。

2. abstract void surfaceCreated(SurfaceHolderholder)

当surface对象创建后,该方法就会被立即调用。

3. abstract void surfaceDestroyed(SurfaceHolderholder)

当surface对象在将要销毁前,该方法会被立即调用。

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

One of the purposes of this class is to provide a surface in which a secondarythread can render into the screen. If you are going to use it this way, youneed to be aware of some threading semantics:

-        All SurfaceView and SurfaceHolder.Callbackmethods will be called from the thread running the SurfaceView's window(typically the main thread of the application). They thus need to correctlysynchronize with any state that is also touched by the drawing thread.

-      You must ensure that the drawingthread only touches the underlying Surface while it is valid -- betweenSurfaceHolder.Callback.surfaceCreated() andSurfaceHolder.Callback.surfaceDestroyed().

这段话很重要,大致意思如下:

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

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

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

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

package com.example.testsurfaceview;

import android.os.Bundle;

import android.app.Activity;

import android.view.Menu;

public class MainActivity extends Activity {

@Override

protected void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

//setContentView(R.layout.activity_main);

setContentView(new MySurfaceView(this));

}

@Override

public boolean onCreateOptionsMenu(Menu menu) {

// Inflate the menu; this adds items to the action bar if it is present.

getMenuInflater().inflate(R.menu.main, menu);

return true;

}

}

2.       分别新建一个线程类,和MySurfaceView类:

MySurfaceView.java

package com.example.testsurfaceview;

import android.content.Context;

import android.view.SurfaceHolder;

import android.view.SurfaceView;

public class MySurfaceView extends SurfaceView

implements

SurfaceHolder.Callback

{

private SurfaceHolder mHolder;

private MyThread myThread;

public MySurfaceView(Context context)

{

super(context);

this.mHolder = this.getHolder(); // 获得SurfaceHolder对象

this.mHolder.addCallback(this); // 添加回调结构SurfaceHolder.Callback

/* 创建一个绘制线程,将holder对象作为参数传入,这样在绘制线程中得到holder对象;

* 进而在绘制线程中通过holder对象获得canvas对象,并在canvas上进行绘制。

* */

this.myThread = new MyThread(mHolder);

}

// 实现SurfaceHolder.Callback接口中的三个方法,都是在主线程中调用,而不是在绘制线程中调用的

@Override

public void surfaceChanged(SurfaceHolder holder, int format, int width,

int height) {

// TODO Auto-generated method stub

}

@Override

public void surfaceCreated(SurfaceHolder holder)

{

// 启动线程。当这个方法调用时,说明Surface已经有效了

this.myThread.SetRun(true);

this.myThread.start();

}

@Override

public void surfaceDestroyed(SurfaceHolder holder)

{

// 结束线程。当这个方法调用时,说明Surface即将要被销毁了

this.myThread.SetRun(false);

}

}

MyThread.java

/*

* 这是一个描绘线程

*/

package com.example.testsurfaceview;

import android.graphics.*;

import android.view.*;

public class MyThread extends Thread

{

private SurfaceHolder mHolder;

private boolean mRun;

public MyThread(SurfaceHolder holder)

{

this.mHolder = holder;

this.mRun = true;

}

@Override

public void run()

{

int counter = 0;

Canvas canvas = null;

while(mRun)

{

try

{

/* 获取canvas对象并锁定 */

canvas = this.mHolder.lockCanvas();

canvas.drawColor(Color.WHITE);    // canvas对象的背景颜色

Paint p = new Paint();                    // 创建画笔

/* 画笔颜色 */

if(counter %2 == 0)

p.setColor(Color.BLACK);

else

p.setColor(Color.RED);

p.setTextSize(30);                            // 文字大小

Rect rect = new Rect(100,50,380,330); // 设置绘画范围

/* 开始绘制 */

canvas.drawRect(rect, p); // 绘矩阵

// 写文字,(point x,point y)

canvas.drawText("Interval = " + (counter++) + " seconds.", 100, 410, p);

Thread.sleep(1000);

}

catch(Exception run)

{

run.printStackTrace();

}

finally

{

if(canvas != null)

{

/*    解除锁定,并提交修改内容 */

this.mHolder.unlockCanvasAndPost(canvas);

}

}

}

}

public boolean IsRun()

{

return this.mRun;

}

public void SetRun(boolean run)

{

this.mRun = run;

}

}

Code:

TestSurfaceView.7z

android surfaceholder的数据,Surface、SurfaceView、SurfaceHolder详解相关推荐

  1. Android实战:CoolWeather酷欧天气(加强版数据接口)代码详解(上)

    -----------------------------------该文章代码已停更,可参考浩比天气(更新于2019/6/25)----------------------------------- ...

  2. Android 各大厂面试题汇总与详解(持续更新)

    介绍 目前网络中出现了好多各种面试题的汇总,有真实的也有虚假的,所以今年我将会汇总各大公司面试比较常见的问题,逐一进行解答.会一直集成,也会收集大家提供的面试题,如有错误,请大家指出,经过排查存在,会 ...

  3. Android消息传递之EventBus 3.0使用详解

    前言: 前面两篇不仅学习了子线程与UI主线程之间的通信方式,也学习了如何实现组件之间通信,基于前面的知识我们今天来分析一下EventBus是如何管理事件总线的,EventBus到底是不是最佳方案?学习 ...

  4. Android低功耗蓝牙(BLE)使用详解

    代码地址如下: http://www.demodashi.com/demo/13390.html 与普通蓝牙相比,低功耗蓝牙显著降低了能量消耗,允许Android应用程序与具有更严格电源要求的BLE设 ...

  5. android自定义view案例,Android自定义View的实现方法实例详解

    一.自绘控件 下面我们准备来自定义一个计数器View,这个View可以响应用户的点击事件,并自动记录一共点击了多少次.新建一个CounterView继承自View,代码如下所示: 可以看到,首先我们在 ...

  6. android底部滑动出现虚拟按键,Android适配底部虚拟按键的方法详解

    Android适配底部虚拟按键的方法详解 发布时间:2020-10-09 05:26:12 来源:脚本之家 阅读:171 作者:yuanzhihui123 最近项目进行适配的时候发现部分(如华为手机) ...

  7. linux 蓝牙 手机遥控器,嵌入式Android小项目之万能手机遥控器详解

    原标题:嵌入式Android小项目之万能手机遥控器详解 在很久很久以前,手机是有红外功能的,后来随着蓝牙技术的成熟,红外逐渐被蓝牙取代,不再是标配了. 红外本身还是有些优点,比如操作简便,成本低.要想 ...

  8. Android 8.0学习(32)---Android 8.0源码目录结构详解

    Android 8.0源码目录结构详解 android的移植按如下流程:     (1)android linux 内核的普通驱动移植,让内核可以在目标平台上运行起来.     (2)正确挂载文件系统 ...

  9. android系统的手机文件夹目录详解

    android系统的手机文件夹目录详解 一.文件夹 1./acct/     系统回收站,删除的系统文件. 2./cache/     缓存 3. /data/      用户的所有程序相关数据   ...

  10. Android 7.0 Audio的Resample过程详解

    Android 7.0 Audio的Resample过程详解 Qidi 2017.02.23 (Markdown & Haroopad) [前言] 处理过音频文件的工程师都知道音频数据存在采样 ...

最新文章

  1. 科普丨一文看懂语音识别的技术原理
  2. Windows Virtual PC RC 发布
  3. gcc编译自定义头文件
  4. wxWidgets第九课 wx绘图工具
  5. 为什么物联网没有杀手级应用
  6. html如何控制弹窗位置,控制弹窗展示顺序
  7. [html] 你了解HTML5的download属性吗?
  8. 7-5 列车厢调度 (25 分)
  9. 文件字符输出流 FileWritter java
  10. oracle 创建一揽子协议,Oracle PO - 模块一揽子采购协议小结
  11. linux查看md5值
  12. 通过python实现同步修改本地电脑时间
  13. 分享2个ICON资源链接
  14. 张家界3天旅游攻略(带你的想象给我游玩一遍)
  15. 【NLP】文本情感分析
  16. PyCharm控制台Problems提示:Typo: In word ‘___‘
  17. java唯一订单号_java高并发下唯一订单号生成器【16位数字订单号】
  18. WiFi大师3.0.9独立可运营版
  19. [阅读笔记] - 秦汉政治
  20. 电路方案分析(二)BLDC驱动和控制电路原理图分析

热门文章

  1. FIR和IIR去噪算法
  2. 2022打造新私域增长涡轮
  3. 网关限流算法及实现总结
  4. 采样坦克4音色库-IK Multimedia SampleTank 4 Sound Library
  5. 十进制转十六进制C语言实现
  6. 主流CTR预估模型的演化及对比
  7. JDBC自我复习之Statement和PreparedStatement的区别
  8. Tutorial-bash
  9. 【各种**问题系列】什么是URL、URN、URI?
  10. vue报错-Error: Cannot find module 'fs/promises'