文章目录
- 前言
- 一、什么是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 来将图像渲染到屏幕上。以下是该渲染流程的关键步骤:
- 初始化 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 操作与渲染共用一个线程 |