这两个方法都属于 TextureView.SurfaceTextureListener 接口,通常在 TextureView 中使用,以响应其底层 Surface 的状态变化。

(图片来源网络,侵删)
onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height)
当一个 TextureView 第一次准备好,并且其底层的 SurfaceTexture 可以被安全地使用时,系统会调用这个方法,这通常意味着 TextureView 已经被添加到视图层次结构中,并且已经测量和布局完成。
参数详解:
| 参数 | 类型 | 描述 |
|---|---|---|
surface |
SurfaceTexture |
最重要的参数,这是一个代表 TextureView 渲染表面的对象,你可以将它传递给其他需要渲染目标的组件,- 相机预览 ( Camera2 API 的 setSurface() 方法)- 视频播放器 ( MediaPlayer.setSurface() 或 ExoPlayer 的相关方法)- OpenGL ES 上下文 ( GLSurfaceView.setEGLSurfaceChooser() 或直接作为 EGL 的渲染目标)一旦你获得了这个 surface,你就可以开始向它绘制内容了。 |
width |
int |
TextureView 当前的宽度,单位是像素,这个值是 TextureView 经过父容器约束和自身 layout_width 设置后计算得出的最终宽度。 |
height |
int |
TextureView 当前的高度,单位是像素,同样,这是经过计算后的最终高度。 |
何时使用?
你通常在这个方法里做以下事情:
- 获取渲染目标:将
surface参数保存下来,用于后续的相机、视频或图形渲染。 - 启动预览/播放:启动相机预览或开始播放视频。
- 开始绘制:如果你使用 OpenGL 或 Canvas 进行自定义绘制,可以在这里开始绘制循环。
示例代码:
// 在你的 Activity 或 Fragment 中实现 TextureView.SurfaceTextureListener
textureView.setSurfaceTextureListener(new TextureView.SurfaceTextureListener() {
@Override
public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) {
Log.d("SurfaceListener", "Surface is available! Size: " + width + "x" + height);
// 1. 保存 surface,稍后使用
mySurface = surface;
// 2. 启动相机预览 (伪代码)
if (cameraManager != null) {
cameraManager.startPreview(surface);
}
// 3. 或者开始 OpenGL 绘制
glRenderer.start(surface, width, height);
}
// ... 其他回调方法
});
onSurfaceTextureDestroyed(SurfaceTexture surface)
当 TextureView 即将被销毁,其底层的 SurfaceTexture 不再可用时,系统会调用这个方法,这通常发生在以下情况:
TextureView从视图层次结构中被移除。Activity被销毁(用户按了返回键)。TextureView被设置为INVISIBLE或GONE。
参数详解:
| 参数 | 类型 | 描述 |
|---|---|---|
surface |
SurfaceTexture |
即将被销毁的 SurfaceTexture 对象。注意:此时这个 surface 已经无效,绝对不能再使用它来进行任何渲染操作(传递给相机或视频播放器),它的存在仅仅是为了让你能够引用它,以便进行一些清理工作。 |
何时使用?
你必须在这个方法里做以下事情:

(图片来源网络,侵删)
- 停止所有使用该 Surface 的操作:这是最重要的步骤!你必须立即停止任何正在向这个
surface渲染的操作,否则可能会导致程序崩溃或产生不可预知的行为。- 停止相机预览 (
camera.stopPreview())。 - 暂停或停止视频播放 (
mediaPlayer.pause()或release())。 - 停止 OpenGL 的绘制循环。
- 停止相机预览 (
- 释放资源:如果持有对这个
surface的引用,现在可以将其置为null,帮助垃圾回收。 - 通知其他组件:通知其他依赖这个
surface的组件,它已经失效了。
示例代码:
textureView.setSurfaceTextureListener(new TextureView.SurfaceTextureListener() {
// ... onSurfaceTextureAvailable ...
@Override
public void onSurfaceTextureDestroyed(SurfaceTexture surface) {
Log.d("SurfaceListener", "Surface is destroyed!");
// 1. 立即停止相机预览
if (cameraManager != null) {
cameraManager.stopPreview();
}
// 2. 停止视频播放
if (mediaPlayer != null) {
mediaPlayer.pause(); // 或者 release()
}
// 3. 停止 OpenGL 绘制
glRenderer.stop();
// 4. 清理引用
mySurface = null; // 假设你之前在 onSurfaceTextureAvailable 中保存了它
}
// ... 其他回调方法 ...
});
其他相关回调(补充)
虽然你的问题只问了 surfacechanged 相关的参数,但完整的 SurfaceTextureListener 还包含另外两个方法,了解它们有助于全面理解生命周期:
onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height)
- 触发时机:当
TextureView的尺寸发生变化时(屏幕旋转、父容器大小改变)被调用。 - 参数:
surface(仍然有效),以及新的width和height。 - 用途:如果你的渲染内容(如相机预览、视频、OpenGL 视口)需要适应新的尺寸,你应该在这里进行相应的调整,重新设置相机的预览尺寸,或者更新 OpenGL 的视口和投影矩阵。
onSurfaceTextureUpdated(SurfaceTexture surface)
- 触发时机:每当
SurfaceTexture的缓冲区被更新时(即有新的一帧数据)被调用,这个回调频率非常高,通常与屏幕刷新率一致(60fps)。 - 参数:
surface(仍然有效)。 - 用途:不常用,如果你需要对每一帧数据进行非常精细的、实时的处理(进行图像分析),可以使用这个回调,但对于大多数应用(如播放视频、显示相机预览),这个回调是多余的,因为渲染机制会自动处理新帧。
总结与最佳实践
| 方法 | 触发时机 | surface 状态 |
主要用途 |
|---|---|---|---|
onSurfaceTextureAvailable |
TextureView 准备就绪 |
可用 | 启动渲染操作(相机、视频、绘制) |
onSurfaceTextureDestroyed |
TextureView 即将被销毁 |
已失效 | 停止所有渲染操作,释放资源 |
onSurfaceTextureSizeChanged |
TextureView 尺寸改变 |
可用 | 调整渲染操作以适应新尺寸 |
onSurfaceTextureUpdated |
每一帧更新时 | 可用 | (高级用法)对每一帧进行处理 |
核心原则:
- 在
Available中启动,在Destroyed中停止。 - 永远不要在
Destroyed的回调中使用传入的surface。 - 正确处理尺寸变化,以避免拉伸或变形。
通过正确实现这些回调,你可以确保你的 TextureView 在各种生命周期状态下都能稳定、高效地工作。

(图片来源网络,侵删)
