Android的SurfaceView和TextureView介绍

文章目录

  • 前言
  • 一、什么是SurfaceView ?
    • 1.1 SurfaceView 使用示例
    • 1.2 SurfaceView 源码概述
    • 1.3 SurfaceView 的构造与初始化
    • 1.4 SurfaceHolder.Callback 回调接口
    • 1.5 SurfaceView 渲染机制
  • 二、什么是TextureView?
    • 2.1 TextureView 使用示例
    • 2.2 TextureView 源码概述
    • 2.3 TextureView 的构造与初始化
    • 2.4 SurfaceTextureListener 回调
    • 2.5 TextureView渲染流程
  • 三、SurfaceView和TextureView区别


前言

一、什么是SurfaceView ?

SurfaceView 是一种用于直接将图形绘制到屏幕的Android组件。与常规的 View 不同,SurfaceView 通过使用一个独立的 Surface 来进行渲染,它不直接依赖于主 UI 线程,而是利用单独的硬件加速的线程进行渲染

1.1 SurfaceView 使用示例

SurfaceView 的常见用法通常是在视频播放、相机预览或实时图形渲染等场景中。以下是一个简单的 SurfaceView 使用示例,它展示了如何在 Android 应用中创建并使用 SurfaceView:

布局 XML 文件 (res/layout/activity_main.xml)

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="match_parent"android:layout_height="match_parent"android:orientation="vertical"><android.view.SurfaceViewandroid:id="@+id/surfaceView"android:layout_width="match_parent"android:layout_height="match_parent" />
</LinearLayout>
import android.os.Bundle;
import android.view.Surface;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import androidx.appcompat.app.AppCompatActivity;public class MainActivity extends AppCompatActivity implements SurfaceHolder.Callback {private SurfaceView surfaceView;private SurfaceHolder surfaceHolder;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);surfaceView = findViewById(R.id.surfaceView);surfaceHolder = surfaceView.getHolder();surfaceHolder.addCallback(this);  // 注册回调}@Overridepublic void surfaceCreated(SurfaceHolder holder) {// 在 Surface 创建时调用,可以在此开始渲染Surface surface = holder.getSurface();}@Overridepublic void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {// 当 Surface 大小或格式改变时调用// 更新渲染内容或调整显示内容}@Overridepublic void surfaceDestroyed(SurfaceHolder holder) {// 在 Surface 销毁时调用// 停止渲染操作并释放资源}
}

在上述示例中,我们首先在布局中定义了一个 SurfaceView,然后通过 surfaceView.getHolder() 获取 SurfaceHolder,并注册了 SurfaceHolder.Callback 接口来处理 Surface 的生命周期。

1.2 SurfaceView 源码概述

SurfaceView 主要用于处理需要高效、实时渲染的场景,例如视频播放、游戏渲染、相机预览等。它的渲染操作由后台线程执行,避免了与主 UI 线程的竞争,提升了性能。

主要类及源码文件
SurfaceView 类位于 frameworks/base/core/java/android/view/SurfaceView.java。
通过 getHolder() 获取与 SurfaceView 关联的 SurfaceHolder。
SurfaceHolder 是一个接口,通过它可以获取与 SurfaceView 关联的 Surface 对象并进行渲染。

1.3 SurfaceView 的构造与初始化

SurfaceView 在初始化时,首先通过 getHolder() 获取 SurfaceHolder,然后注册回调接口来处理 Surface 的生命周期。具体代码如下:

public SurfaceView(Context context) {super(context);mSurfaceHolder = getHolder(); // 获取 SurfaceHoldermSurfaceHolder.addCallback(this); // 注册回调
}

在此过程中,getHolder() 返回一个 SurfaceHolder 对象,该对象用于管理与 SurfaceView 关联的 Surface。SurfaceHolder.Callback 回调接口的实现帮助我们在 Surface 创建、改变和销毁时执行相应的操作。

1.4 SurfaceHolder.Callback 回调接口

SurfaceHolder.Callback 是一个关键接口,SurfaceView 使用它来处理与 Surface 相关的生命周期事件。它包括三个主要回调方法:

  • surfaceCreated(SurfaceHolder holder)
    surfaceCreated() 方法在 Surface 被创建时调用。此时,SurfaceView 可以开始渲染图形内容。
@Override
public void surfaceCreated(SurfaceHolder holder) {// 此时 Surface 创建成功,可以开始渲染Surface surface = holder.getSurface();// 进行图形渲染,通常启动渲染线程
}
  • surfaceChanged(SurfaceHolder holder, int format, int width, int height)
    当 Surface 的格式或尺寸发生变化时,surfaceChanged() 会被调用。此时,应用程序可以根据新的尺寸调整渲染内容。
@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {// 处理 Surface 格式或尺寸变化
}
  • surfaceDestroyed(SurfaceHolder holder)
    当 Surface 被销毁时,surfaceDestroyed() 会被调用。此时,应用程序应停止渲染操作并释放资源。
@Override
public void surfaceDestroyed(SurfaceHolder holder) {// 停止渲染线程并释放资源
}

1.5 SurfaceView 渲染机制

SurfaceView 的渲染由后台线程处理,渲染过程包括锁定 Canvas、进行绘制并提交结果。

后台线程Surface
SurfaceView 的渲染并不在主 UI 线程中进行,而是通过后台线程来完成的。这是为了避免 UI 线程的阻塞,确保 UI 能够流畅运行。

SurfaceView 在后台线程中会使用 SurfaceHolder.lockCanvas() 获取 Canvas 对象,然后进行图形绘制。绘制完成后,通过 SurfaceHolder.unlockCanvasAndPost() 提交更新。

public void render(Surface surface) {Canvas canvas = null;try {canvas = holder.lockCanvas(null); // 锁定 Canvasif (canvas != null) {// 在 Canvas 上绘制图形内容canvas.drawColor(Color.BLACK);  // 清屏// 绘制其他内容}} finally {if (canvas != null) {holder.unlockCanvasAndPost(canvas); // 提交绘制结果}}
}

二、什么是TextureView?

TextureView 用于显示一个内容的纹理。它和 SurfaceView 的功能类似,但实现方式有所不同。
TextureView 允许将 OpenGL 渲染的内容、视频帧或其他图像直接作用在 UI 线程上,并且能够在任何地方进行动画、旋转或缩放,而不仅限于一个固定的 Surface。
相较于 SurfaceView,TextureView 在灵活性和控制方面有更多的优势。

2.1 TextureView 使用示例

下面是一个简单的 TextureView 使用示例。

public class MyActivity extends AppCompatActivity {private TextureView textureView;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);textureView = findViewById(R.id.textureView);textureView.setSurfaceTextureListener(new TextureView.SurfaceTextureListener() {@Overridepublic void onSurfaceCreated(SurfaceTexture surface, int width, int height) {// Surface 创建时,初始化 SurfaceSurface newSurface = new Surface(surface);// 可以在这里执行渲染操作}@Overridepublic void onSurfaceChanged(SurfaceTexture surface, int width, int height) {// Surface 改变大小时}@Overridepublic void onSurfaceDestroyed(SurfaceTexture surface) {// Surface 销毁时}@Overridepublic void onSurfaceUpdated(SurfaceTexture surface) {// 每次 Surface 更新时调用}});}
}

2.2 TextureView 源码概述

以下是 TextureView 源码概述的核心内容,详细分析其结构和工作原理。

1、关键类和接口
TextureView 类:TextureView 是整个视图系统的核心,它继承自 View 类。它的主要职责是通过 SurfaceTexture 渲染图像内容,并通过 Surface 显示。

SurfaceTexture:SurfaceTexture 是与 OpenGL 渲染绑定的对象,用于显示图像流。它为 TextureView 提供了一个接口,通过它可以将渲染内容传输到 SurfaceView 或 TextureView。

Surface:Surface 是 Android 用于图形渲染的基本容器。SurfaceTexture 通过 Surface 输出图形数据,TextureView 通过此 Surface 显示内容。

SurfaceTextureListener 接口:该接口提供了与 SurfaceTexture 生命周期相关的回调方法,开发者可以通过实现该接口来响应 Surface 创建、更新和销毁的事件。

2.3 TextureView 的构造与初始化

1、构造函数
TextureView 提供了多个构造函数,可以通过不同的方式初始化对象。最常见的构造函数是:

public TextureView(Context context) {super(context);init();
}

在构造函数中,TextureView 被初始化并配置了所需的 SurfaceTexture。通过调用 init() 方法,SurfaceTexture 和 Surface 将被创建,并为后续的图像渲染做好准备。

private void init() {// 创建 SurfaceTexture 对象mSurfaceTexture = new SurfaceTexture(false);// 创建 Surface 对象mSurface = new Surface(mSurfaceTexture);// 设置视图的缓冲区和其他默认参数setOpaque(true);  // 设置是否为不透明mSurfaceTextureListener = null;
}

2. SurfaceTexture 和 Surface 的创建
TextureView 的核心是通过 SurfaceTexture 来获取渲染的数据流,并通过 Surface 来显示这些图像内容。创建 SurfaceTexture 和 Surface 的代码如下:

mSurfaceTexture = new SurfaceTexture(false);  // 创建 SurfaceTexture 实例
mSurface = new Surface(mSurfaceTexture);     // 使用 

SurfaceTexture 创建 Surface
SurfaceTexture 是渲染内容的承载者,它接收渲染引擎(如 OpenGL)的输出,并将其传递给 Surface。
Surface 是渲染结果的显示容器,TextureView 通过该 Surface 来显示图像。
SurfaceTexture 的参数 false 表示它是一个非透明的纹理。在大多数情况下,使用非透明纹理可以获得更好的渲染性能。

2.4 SurfaceTextureListener 回调

TextureView 还提供了一个接口 SurfaceTextureListener,用于接收 SurfaceTexture 生命周期的回调事件。这个回调接口包含了多个方法,可以在 SurfaceTexture 创建、更新或销毁时进行处理。

  • onSurfaceCreated(SurfaceTexture surface, int width, int height):当 SurfaceTexture 创建时调用。此时可以开始渲染内容。
  • onSurfaceChanged(SurfaceTexture surface, int width, int height):当 SurfaceTexture 尺寸发生变化时调用。可以用来更新渲染内容或调整显示尺寸。
  • onSurfaceDestroyed(SurfaceTexture surface):当 SurfaceTexture 销毁时调用,可以在此时释放资源。
  • onSurfaceUpdated(SurfaceTexture surface):每次 SurfaceTexture 更新时调用,用于通知渲染更新。

2.5 TextureView渲染流程

TextureView 的渲染流程主要依赖于 SurfaceTexture 和 Surface 来将图像渲染到屏幕上。以下是该渲染流程的关键步骤:

  1. 初始化 SurfaceTexture 和 Surface:

TextureView 在初始化时创建一个 SurfaceTexture 对象,该对象用于接收图形数据。
然后将 SurfaceTexture 封装为 Surface,Surface 用于显示图像内容。

  1. 图像数据传递到 SurfaceTexture:

图形引擎(如 OpenGL)将渲染结果传递给 SurfaceTexture,这些数据会被存储在 SurfaceTexture 中。

3.SurfaceTexture 更新:

一旦 SurfaceTexture 中的图像数据更新,TextureView 会收到通知,并准备将新图像内容显示出来。
SurfaceTexture 会将最新的图像数据传递给关联的 Surface。

  1. 显示图像内容:

Surface 在 TextureView 上渲染和显示图像内容。此时,TextureView 会将图像数据呈现到屏幕上。

三、SurfaceView和TextureView区别

特性SurfaceViewTextureView
渲染方式渲染内容直接通过硬件层输出,不经过 UI 层,绕过屏幕缓冲区通过 SurfaceTexture 渲染内容,经过 UI 层(即视图层)显示
性能高性能,适合要求低延迟、高帧率的应用,如视频播放、实时游戏等性能相对较低,适用于对 UI 层交互、动画有要求的应用
渲染效率渲染在独立的硬件层,减少 UI 线程负担,图形处理独立渲染经过 UI 层,渲染性能相对较低,可能会受到 UI 层操作影响
硬件加速支持直接使用硬件加速,不依赖 UI 线程,适合高效图形渲染使用硬件加速,但图形渲染受 UI 线程限制
变换与动画支持不支持内建的图像变换,若需动画或变换需要依赖外部图形库如 OpenGL支持矩阵变换(旋转、缩放、平移等),支持视图动画和动态效果
视图层级与嵌套渲染层与 UI 层分离,不能与其他视图进行直接交互或嵌套渲染内容在 UI 层,可以和其他视图层级交互、嵌套和变换
生命周期管理通过 SurfaceHolder.Callback 回调接口管理 Surface 的生命周期通过 SurfaceTextureListener 回调接口管理 SurfaceTexture 生命周期
适用场景适用于视频播放、实时游戏渲染等对性能要求高的应用适用于动态变换、动画和需要与 UI 层交互的场景(如视频展示、图像旋转)
支持的 UI 操作不支持直接与 UI 层进行交互(例如点击、动画、视图更新等)支持与 UI 层的交互,支持视图动画(例如 setTransform() 变换)
硬件渲染与UI渲染渲染直接在硬件层进行,不依赖 UI 线程渲染通过 UI 层进行,UI 线程参与渲染处理,可能有性能开销
透明背景支持不直接支持透明背景支持透明背景,适合需要透明或部分透明效果的应用
支持多层显示支持多层显示,但通常是通过 Surface 进行不同图层显示支持多图层显示,允许将多个 TextureView 嵌套并渲染不同内容
显示内容更新渲染内容更新较为简单,依赖 lockCanvas、unlockCanvasAndPost显示内容更新通过 SurfaceTexture 更新,内容刷新通过 updateTexImage()
硬件解码视频非常适合硬件解码视频,视频数据直接渲染到硬件层不如 SurfaceView 高效,视频数据需要通过 SurfaceTexture 渲染
UI 线程影响不会受到 UI 线程影响,独立的渲染线程渲染依赖 UI 线程,可能会影响 UI 线程的流畅性,特别是在高负荷情况下
可嵌入到布局中不可以直接与其他视图一起进行布局可以像普通视图一样嵌入布局,支持与其他视图交互和变换
旋转与缩放不支持内建旋转、缩放等变换,需使用外部图形库支持内建旋转、缩放和其他变换,支持多种变换方式
API 支持支持大部分 Android 设备,并且对硬件解码支持较好支持大部分 Android 设备,适合需要在视图层做渲染处理的场景
渲染线程在独立线程中进行渲染,UI 线程与渲染分离渲染在 UI 线程中进行,UI 操作与渲染共用一个线程

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/web/62602.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

vscode 排除文件夹搜索

排除的文件夹 node_modules/,dist/

优雅的@ObservedV2和@Trace装饰器

Hello&#xff0c;大家好&#xff0c;我是 V 哥。在HarmonyOS NEXT开发中&#xff0c;ObservedV2装饰器和Trace装饰器是用于状态管理的两个装饰器&#xff0c;它们在HarmonyOS应用开发中用于增强对类对象中属性的观测能力。如果你学过观察者模式的原理&#xff0c;你会更容易理…

备战蓝桥第一天 验证回文串 杨辉三角

LCR 018. 验证回文串 - 力扣&#xff08;LeetCode&#xff09; 涉及的函数&#xff1a; int isalnum ( int c ); 检查字符是否为字母数字 int tolower ( int c ); 将大写字母转换为小写 void reverse (BidirectionalIterator first, BidirectionalIterator last); 反转区域中…

【实战】提升List性能方法有几何

在内存中的 List<T> 上使用 LINQ 查询时&#xff0c;加索引并不像数据库那样有内置支持&#xff0c;但可以通过以下方式提高查询性能&#xff1a; 1. 手动构建索引 可以手动构建一个字典 (Dictionary<TKey, TValue>)&#xff0c;将需要查询的字段作为键&#xff0…

一款免费、简单、快速的JS打印插件,web 打印组件,基于JavaScript开发,支持数据分组,快速分页批量预览,打印,转pdf,移动端,PC端

前言 在数字化办公时代&#xff0c;打印需求呈现多样化和复杂化的趋势。现有的打印软件往往存在cao作繁琐、兼容性差、功能单一等问题&#xff0c;难以满足现代企业高效、灵活的打印需求。 为了解决这些痛点&#xff0c;一款简单、高效、多功能的打印插件成为了迫切需求。 介…

Python pywin32库详解

一、引言 在Python编程中&#xff0c;有时候需要与Windows操作系统进行交互&#xff0c;执行一些特定的系统操作或操作 Windows 应用程序。这时&#xff0c;pywin32库就成为了一个非常强大的工具。pywin32库提供了对Windows API的访问&#xff0c;使得Python开发者能够在Windo…

Uniapp的vue、nvue、uvue后缀名区别

在 UniApp 中&#xff0c;.vue、.nvue 和 .uvue 是不同的文件后缀名&#xff0c;每个文件格式的使用场景和兼容性略有不同。下面是每个文件后缀的详细解释以及它们的兼容性&#xff1a; 1. .vue 文件 定义&#xff1a;.vue 是标准的 Vue 单文件组件格式&#xff0c;主要用于基…

TCP/IP杂记

TCP三次握手、四次挥手 从应用角度&#xff0c;不用多考虑为什么有三次&#xff0c;遵循标准即可。 ubuntu 下 wireshark安装&#xff1a; sudo add-apt-repository universe sudo apt install wireshark 三次握手实证&#xff1a; 第一次握手的情况如下&#xff1a;&#…

Vue前端开发-接收跳转参数

路由携带参数跳转到目标页面后&#xff0c;页面组件可以接收到携带传入的参数&#xff0c;接收的方式与携带的方式相关&#xff0c;如果是采用查询字符串方式携带&#xff0c;那么可以通过路由中的query对象获取到参数&#xff0c;如果是其他方式&#xff0c;通常都是通过路由中…

力扣--LCR 177.撞色搭配

题目 整数数组 sockets 记录了一个袜子礼盒的颜色分布情况&#xff0c;其中 sockets[i] 表示该袜子的颜色编号。礼盒中除了一款撞色搭配的袜子&#xff0c;每种颜色的袜子均有两只。请设计一个程序&#xff0c;在时间复杂度 O(n)&#xff0c;空间复杂度O(1) 内找到这双撞色搭配…

[ComfyUI]批量生成图片的节点:输入一个prompt列表批量生成图像

文章目录 1.参考资料2.两个节点的部署FizzNodes节点comfyui-mixlab-nodes 生成的结果展示 1.参考资料 如何使用ComfyUI一次批量生成不同内容的图片 ComfyUI工作流】随机提示词批量出图&#xff0c;懒人刷图福音&#xff0c;根据提示 2.两个节点的部署 FizzNodes节点 fizzn…

【实操GPT-SoVits】声音克隆模型图文版教程

项目github地址&#xff1a;https://github.com/RVC-Boss/GPT-SoVITS.git官方教程&#xff1a;https://www.yuque.com/baicaigongchang1145haoyuangong/ib3g1e/tkemqe8vzhadfpeu本文旨在迅速实操GPT-SoVits项目&#xff0c;不阐述技术原理&#xff08;后期如果有时间研究&#…

5G模组AT命令脚本-关闭模组的IP过滤功能

关闭模组的IP过滤功能 关闭模组的IP过滤功能 5G 模组通常使用nat方式为 下挂设备或上位机提供上网服务&#xff0c;默认情况&#xff0c;不做NAt的包无法经由 模组转发&#xff0c;如果禁掉这个限制 &#xff0c;可使用本文中的配置命令本脚本用于关闭模组的IP过滤功能&#xf…

JAVA (Springboot) i18n国际化语言配置

JAVA i18n国际化语言配置 一、简介二、功能三、Java配置国际化步骤四、Java国际化配置工具类五、Spring Boot配置六、测试 一、简介 在Java中&#xff0c;国际化&#xff08;Internationalization&#xff0c;通常简称为i18n&#xff09;是一个过程&#xff0c;它允许应用程…

如何创建基于udp的客户端和服务端

1.先创建好udpServer.hpp、udpServer.cc、udpClient.hpp、udpClient.cc的框架。 #pragma once #include <string> #include <iostream> #include <sys/types.h> #include <sys/socket.h> #include <unistd.h> #include <cerrno> #include…

【上线文档】系统上线方案模板,计算机系统上线保障计划,系统运维信息系统运行保障方案,系统上线方案模板(Word原件)

一、项目背景和目标 二、项目需求分析 2.1 功能需求 2.2 非功能需求 三、系统设计 3.1 系统架构设计 3.2 数据库设计 3.3 接口设计 3.4 用户界面设计 四、系统开发 4.1 开发环境搭建 4.2 业务逻辑开发 4.3 数据库实现 4.4 接口实现 4.5 用户界面实现 五、系统测…

大模型应用的数字能源数据集

除了尚须时日的量子计算解决算力效率和能源问题&#xff0c;以及正在路上的超越transformer的全新模型架构外&#xff0c;无疑是“数据集”&#xff0c;准确讲是“高质量大规模多样性的数据集”。数据集是大模型发展的核心要素之一&#xff0c;是大计算的标的物&#xff0c;是实…

【OpenCV】图像转换

理论 傅立叶变换用于分析各种滤波器的频率特性。对于图像&#xff0c;使用 2D离散傅里叶变换&#xff08;DFT&#xff09; 查找频域。快速算法称为 快速傅立叶变换&#xff08;FFT&#xff09; 用于计算DFT。 Numpy中的傅立叶变换 首先&#xff0c;我们将看到如何使用Numpy查…

如何使用Java编写Jmeter函数

Jmeter 自带有各种功能丰富的函数&#xff0c;可以帮助我们进行测试&#xff0c;但有时候提供的这些函数并不能满足我们的要求&#xff0c;这时候就需要我们自己来编写一个自定义的函数了。例如我们在测试时&#xff0c;有时候需要填入当前的时间&#xff0c;虽然我们可以使用p…

【2024版】最新kali linux入门及常用简单工具介绍(非常详细)从零基础入门到精通,看完这一篇就够了

前言 相信很多同学了解到和学习网络安全的时候都听过kali系统&#xff0c;大家都称之为黑客最喜爱的系统&#xff0c;那么什么是kali&#xff0c;初学者用kali能做些什么&#xff0c;大白我将在本文中做详细的介绍&#xff1a; 一、kali linux是什么&#xff1f; Kali Linux…