Android中的Android中的Surface和SurfaceView

2023-05-16

 
 
一、什么是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

 
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Android中的Android中的Surface和SurfaceView 的相关文章

  • Android Studio 3.0 Canary 9 - 无法解析包

    我在 Android Studio 3 0 Canary 9 中遇到几个错误 这些错误是 无法解析 android 软件包 下面列出了一些错误 我刚刚安装了 SDK 的所有额外软件包 但仍然收到 gradle 构建错误 Error 82 1
  • 类型容器“Android 依赖项”引用不存在的库 android-support-v7-appcompat/bin/android-support-v7-appcompat.jar

    我在尝试在我的项目中使用 Action Bar Compat 支持库时遇到了某种错误 我不知道出了什么问题 因为我已按照此链接中的说明进行操作 gt http developer android com tools support libr
  • 卸载后 Web 应用程序不显示“添加到主屏幕”

    这是我第一次创建网络应用程序 我设法解决了这个问题 所以我得到了实际的 chrome 提示 将其添加到主屏幕 然后我从手机上卸载了该网络应用程序 因为我想将其展示给我的同事 但是 屏幕上不再出现提示 问题 这是有意为之的行为还是我的应用程序
  • Android 30+ 中的视频捕获意图 - 只有所有者才能与待处理项目交互

    我正在尝试在我的应用程序上捕获视频 它可以在 android API 30 以下运行 但不能在 30 以上运行 似乎在 sdk 30 之后 android 不允许完全读取外部存储 作用域存储 我目前遇到这个错误 java lang Ille
  • 是否必须删除 Intent extra?

    这可能是一个愚蠢的问题 但是是否有一条规则规定消费活动必须显式删除 Intent 额外内容 或者只有在回收 Intent 对象时才如此 换句话说 如果我总是通过执行以下操作来链接到下一个活动 Intent i new Intent MyCu
  • 在 HTTPResponse Android 中跟踪重定向

    我需要遵循 HTTPost 给我的重定向 当我发出 HTTP post 并尝试读取响应时 我得到重定向页面 html 我怎样才能解决这个问题 代码 public void parseDoc final HttpParams params n
  • 如何使用 Cordova 获取当前安装的应用程序的版本?

    我已经找到了应用程序可用性插件 https github com ohh2ahh AppAvailability它主要检查用户是否在其设备上安装了某个应用程序 是否有可能获得应用程序的当前版本 开发者名称 重要 以及所有可能的信息 一般来说
  • Android:捕获的图像未显示在图库中(媒体扫描仪意图不起作用)

    我遇到以下问题 我正在开发一个应用程序 用户可以在其中拍照 附加到帖子中 并将图片保存到外部存储中 我希望这张照片也显示在图片库中 并且我正在使用媒体扫描仪意图 但它似乎不起作用 我在编写代码时遵循官方的Android开发人员指南 所以我不
  • 无法展开 RemoteViews - 错误通知

    最近 我收到越来越多的用户收到 RemoteServiceException 错误的报告 我每次给出的堆栈跟踪如下 android app RemoteServiceException Bad notification posted fro
  • 在gradle插件中获取应用程序变体的包名称

    我正在构建一个 gradle 插件 为每个应用程序变体添加一个新任务 此新任务需要应用程序变体的包名称 这是我当前的代码 它停止使用最新版本的 android gradle 插件 private String getPackageName
  • 你的CPU不支持NX

    我刚刚下载了 android studio 但是我遇到了一个问题 当我运行它时 它说你的 cpu 不支持 NX 我应该怎么办 NX 或实际上是 NX 处理器位 是处理器的一项功能 有助于保护您的 PC 免受恶意软件的攻击 当此功能未启用并且
  • 在两个活动之间传输数据[重复]

    这个问题在这里已经有答案了 我正在尝试在两个不同的活动之间发送和接收数据 我在这个网站上看到了一些其他问题 但没有任何问题涉及保留头等舱的状态 例如 如果我想从 A 类发送一个整数 X 到 B 类 然后对整数 X 进行一些操作 然后将其发送
  • Android Studio 0.4.3 Eclipse项目没有gradle

    在此版本之前 在 Android Studio 中按原样打开 Eclipse 项目似乎很容易 无需任何转换 我更喜欢 Android Studio 环境 但我正在开发一个使用 eclipse 作为主要 IDE 的项目 我不想只为这个项目下载
  • Android访问远程SQL数据库

    我可以直接从 Android 程序访问远程 SQL 数据库 在网络服务器上 吗 即简单地打开包含所有必需参数的连接 然后执行 SQL 查询 这是一个私人程序 不对公众开放 仅在指定的手机上可用 因此我不担心第三方获得数据库访问权限 如果是这
  • 我的设备突然没有显示在“Android 设备选择器”中

    我正在使用我的三星 Galaxy3 设备来测试过去两个月的应用程序 它运行良好 但从今天早上开始 当我将设备连接到系统时 它突然没有显示在 Android 设备选择器 窗口中 我检查过 USB 调试模式仅在我的设备中处于选中状态 谁能猜出问
  • 一次显示两条Toast消息?

    我希望在一个位置显示一条 Toast 消息 并在另一位置同时显示另一条 Toast 消息 多个 Toast 消息似乎总是按顺序排队和显示 是否可以同时显示两条消息 是否有一种解决方法至少可以提供这种外观并且不涉及扰乱活动布局 Edit 看来
  • Firebase 添加新节点

    如何将这些节点放入用户节点中 并创建另一个节点来存储帖子 我的数据库参考 databaseReference child user getUid setValue userInformations 您需要使用以下代码 databaseRef
  • 如何将 google+ 登录集成到我的 Android 应用程序中?

    大家好 实际上我需要通过我的应用程序从 google 登录人们 现在我阅读了 google 上的文档 其中指出 要允许用户登录 请将 Google Sign In 集成到您的应用中 初始化 GoogleApiClient 对象时 请求 PL
  • 节拍匹配算法

    我最近开始尝试创建一个移动应用程序 iOS Android 它将自动击败比赛 http en wikipedia org wiki Beatmatching http en wikipedia org wiki Beatmatching 两
  • 强制 Listview 不重复使用视图(复选框)

    我做了一个定制Listview 没有覆盖getView 方法 Listview 中的每个项目都具有以下布局 联系布局 xml

随机推荐

  • python 读取文件、并以十六进制的方式写入到新文件

    usr bin env python infile 61 file 34 in mp3 34 34 rb 34 outfile 61 file 34 out txt 34 34 wb 34 def main while 1 c 61 inf
  • perl的内置函数scalar

    scalar可以求数组的长度 xff0c 但是 xff0c 在scalar的说明里面并没有这一项 Forces EXPR to be interpreted in scalar context and returns the value o
  • sqlalchemy批量删除数据、全量删除

    问题 xff1a sqlalchemy如何批量删除多条数据 解决 xff1a 使用参数synchronize session 61 False xff0c 或for循环 方法 xff1a users 61 self db query Use
  • 经典的同态滤波算法的优化及其应用参数配置。

    同态滤波 xff0c 网络上有很多文章提到过这个算法 xff0c 我们摘取百度的一段文字简要的说明了该算法的核心 xff1a 同态滤波是一种减少低频增加高频 xff0c 从而减少光照变化并锐化边缘或细节的图像滤波方法 关于该算法 xff0c
  • Trajectory following with MAVROS OFFBOARD on Raspberry Pi

    原文链接 Trajectory following with MAVROS OFFBOARD on Raspberry Pi Jaeyoung Lim August 10 2016 404warehouse Small Projects B
  • 职位介绍 之 嵌入式开发工程师

    笔者电子信息专业硕士毕业 xff0c 获得过多次电子设计大赛 大学生智能车 数学建模国奖 xff0c 现就职于南京某半导体芯片公司 xff0c 从事硬件研发 xff0c 电路设计研究 对于学电子的小伙伴 xff0c 深知入门的不易 xff0
  • Elementui el-dialog 组件我又学会了一种新的用法

    1 新建弹窗Form vue文件 将visible属性设置为true lt template gt lt div gt lt el dialog title 61 34 提示 34 visible 61 34 true 34 width 6
  • webpack系列——实现一个行内样式px转vw的loader

    需求 自从有了postcss来处理css文件 xff0c 我们可以快速进行网站适配的开发 xff0c 只需要改改参数 xff0c 样式按照设计稿的px写 xff0c webpack编译自动转换成rem或者vw等 但是 xff0c 标签内的p
  • Scrapy爬虫 - 获取知乎用户数据

    2016 04 10 Scrapy爬虫 获取知乎用户数据 安装Scrapy爬虫框架 关于如何安装Python以及Scrapy框架 xff0c 这里不做介绍 xff0c 请自行网上搜索 初始化 安装好Scrapy后 xff0c 执行 scra
  • 百度云下载的压缩吧损坏问题解决

    有时用百度云下载压缩包回来之后会出现损坏不能解压的问题 xff0c 比如 xff1a 1 使用网页的批量下载 xff0c 此时百度云会压缩成一个包 xff0c 格式为zip xff0c 而下载下载回来之后用WinRAR解压就会出现CRC校验
  • 理解BPDU Guard的意义(BPDU Guard在全局配置与接口配置上的区别)

    BPDU Guard xff08 BPDU保护 xff09 xff0c 简单的讲它的意义就是一个不该接收 BPDU的端口 xff0c 比如被启动了 portfast的端口 xff0c 一旦收到 BPDU报文 xff0c 那么 BPDU保护功
  • frida hook java原生算法同时打印调用堆栈

    coding UTF 8 import frida sys jsCode 61 34 34 34 function showStacks Java perform function send Java use 34 android util
  • 步步为营 .NET 设计模式学习笔记 十六、Facade(外观模式)

    概述 在软件开发系统中 xff0c 客户程序经常会与复杂系统的内部子系统之间产生耦合 xff0c 而导致客户程序随着子系统的变化而变化 那么如何简化客户程序与子系统之间的交互接口 xff1f 如何将复杂系统的内部子系统与客户程序之间的依赖解
  • tld 标签元素

    每个自定义标签都必须在tld文件中声明 xff0c tld文件只不过是一个XML文件 根元素是 lt taglib gt xff0c 它包含一个或者多个 lt tag gt 标签 xff0c 该元素用来声明定制标签 TLD 文件中的元素标签
  • cuda中用cublas库做矩阵乘法

    这里矩阵C 61 A B xff0c 原始文档给的公式是C 61 alpha A B 43 beta C xff0c 所以这里alpha 61 1 xff0c beta 61 0 主要使用cublasSgemm这个函数 xff0c 这个函数
  • cv_bridge中的编码模式与实现

    image encodings cpp文件是关于图像编码模式的源文件 xff0c 其中规定了RGB的图像以及深度图的编码模式 该编码文件image encodings cpp所依赖的头文件图 命令空间 sensor msgs image e
  • Pixhawk进阶开发

    使用者 初见Pixhawk 大家知道Pix是一个出色的开源飞控 xff0c 那到底什么是Pixhawk呢 xff0c 它有那些种类 它的硬件是怎么设计的 xff0c 软件是基于什么方式设计的 xff0c 我们怎么连接 初始化配置 怎么调节参
  • Java程序心得体会

    学习Java是一件快乐的事情 xff0c 刚开始学习的时候还有点难 xff0c 后来慢慢熟悉了Java的程序操作 xff0c 在错误中获得技巧 xff0c 一次又一次的失败 xff0c 让我对Java产生了兴趣 xff0c 现在对Java既
  • linux网卡顺序发生变化,(linux)复制的虚拟机网卡eth0变成了eth1或其他名称后修正方法...

    正在使用的虚拟机 xff0c 复制之后 xff0c 发现网卡名称发生了变化 xff0c 修正方法如下 xff1a 比如eth0变成了eth1 xff1a ifconfig xff1a udev动态管理设备文件 xff1a cat etc u
  • Android中的Android中的Surface和SurfaceView

    一 什么是Surface 简单的说Surface对应了一块屏幕缓冲区 xff0c 每个window对应一个Surface xff0c 任何View都要画在Surface上 传统的view共享一块屏幕缓冲区 xff0c 所有的绘制必须在UI线