Android的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.SurfaceView android: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; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); surfaceView = findViewById(R.id.surfaceView); surfaceHolder = surfaceView.getHolder(); surfaceHolder.addCallback(this); // 注册回调 } @Override public void surfaceCreated(SurfaceHolder holder) { // 在 Surface 创建时调用,可以在此开始渲染 Surface surface = holder.getSurface(); } @Override public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { // 当 Surface 大小或格式改变时调用 // 更新渲染内容或调整显示内容 } @Override public 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(); // 获取 SurfaceHolder mSurfaceHolder.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); // 锁定 Canvas if (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; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); textureView = findViewById(R.id.textureView); textureView.setSurfaceTextureListener(new TextureView.SurfaceTextureListener() { @Override public void onSurfaceCreated(SurfaceTexture surface, int width, int height) { // Surface 创建时,初始化 Surface Surface newSurface = new Surface(surface); // 可以在这里执行渲染操作 } @Override public void onSurfaceChanged(SurfaceTexture surface, int width, int height) { // Surface 改变大小时 } @Override public void onSurfaceDestroyed(SurfaceTexture surface) { // Surface 销毁时 } @Override public 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 来将图像渲染到屏幕上。以下是该渲染流程的关键步骤:
初始化 SurfaceTexture 和 Surface:
TextureView 在初始化时创建一个 SurfaceTexture 对象,该对象用于接收图形数据。
然后将 SurfaceTexture 封装为 Surface,Surface 用于显示图像内容。
图像数据传递到 SurfaceTexture:
图形引擎(如 OpenGL)将渲染结果传递给 SurfaceTexture,这些数据会被存储在 SurfaceTexture 中。
3.SurfaceTexture 更新:
一旦 SurfaceTexture 中的图像数据更新,TextureView 会收到通知,并准备将新图像内容显示出来。
SurfaceTexture 会将最新的图像数据传递给关联的 Surface。
显示图像内容:
Surface 在 TextureView 上渲染和显示图像内容。此时,TextureView 会将图像数据呈现到屏幕上。
三、SurfaceView和TextureView区别
特性 | SurfaceView | TextureView |
---|---|---|
渲染方式 | 渲染内容直接通过硬件层输出,不经过 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 操作与渲染共用一个线程 |
到此这篇关于Android的SurfaceView和TextureView介绍的文章就介绍到这了,更多相关Android SurfaceView和TextureView内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!