onSurfaceTextureAvailable 没有回调

0 阅读4分钟

onSurfaceTextureAvailable 没有回调,通常和 TextureView硬件加速状态、视图可见性、监听器注册时机,以及视图是否已附加到窗口这几方面有关。下面是按排查优先级整理的原因和解决方法。

🔍 首选排查清单:检查硬件加速

这是最常见的原因,尤其容易出现在项目迁移或配置混乱时。

  • 确保硬件加速已开启TextureView 只能在硬件加速的窗口中正常工作。如果应用或 Activity 的硬件加速被关闭,TextureView 将不会渲染任何内容,相关回调也不会执行。
    • 检查 AndroidManifest.xml<application><activity> 标签下是否误设置了 android:hardwareAccelerated="false"。将其删除或显式设为 true
    • 检查布局文件中 TextureViewandroid:layerType 属性,不能设置为 software
    • 如果上述配置都正确,可以在代码中动态确认硬件加速是否可用:
      if (textureView.isHardwareAccelerated()) {
          // 硬件加速已启用
      }
      

👁️ 检查视图可见性

如果 TextureView 在设置监听器时是不可见View.INVISIBLEView.GONE)或尺寸为 0,系统可能不会为其创建 SurfaceTexture

  • 确保设置监听器时 TextureView 可见且有有效尺寸
  • 如果 TextureView 初始是隐藏的,请在将其可见性设置为 VISIBLE 之后,再注册监听器,或检查监听器是否已正确注册。

⏱️ 检查监听器注册时机

注册监听器的时机很关键。如果在 SurfaceTexture 已经准备就绪之后才设置监听器,回调将不会被触发。

  • 尽早注册:建议在 onCreate()onViewCreated() 中,视图初始化完成后立即调用 setSurfaceTextureListener()。如果延迟到用户点击等操作时才设置,可能已错过回调时机。
  • 处理已就绪的情况:如果注册监听器时 SurfaceTexture 已存在,回调不会再次触发。建议在注册后主动检查,并手动调用初始化逻辑:
    textureView.setSurfaceTextureListener(listener);
    // 防止监听器设置前 SurfaceTexture 已就绪,导致回调不执行
    if (textureView.isAvailable()) {
        listener.onSurfaceTextureAvailable(
            textureView.getSurfaceTexture(),
            textureView.getWidth(),
            textureView.getHeight()
        );
    }
    
    这个防御性检查可以覆盖很多因时序问题导致的回调丢失场景。

🌳 检查视图层级与生命周期

  • 确保视图已附加到窗口SurfaceTexture 只有在 TextureView 被添加到窗口(即 onAttachedToWindow() 被调用)之后才可用。如果 TextureView 没有正确添加到视图树,回调不会触发。
  • 自定义 ViewGroup 的问题:将 TextureView 放在自定义 ViewGroup 中时,如果 ViewGroup 的初始化或测量逻辑有问题,可能导致 TextureView 无法正确附加。可尝试将 TextureView 直接放在布局中测试,以定位问题。
  • Fragment 中的问题:在 Fragment 中,确保在 onViewCreated 或之后才操作视图。如果在 onCreateView 返回之前就尝试设置监听器,视图可能还未完全创建。

⚙️ 检查 SDK 版本配置

在项目迁移后,如果 build.gradleAndroidManifest.xml 中的 SDK 版本配置不一致,也可能导致回调失败。

  • 统一配置:在 build.gradle 中明确指定 minSdkVersiontargetSdkVersion,并移除 AndroidManifest.xml 中的 <uses-sdk> 标签,避免冲突。

🧩 其他原因与解决方案

  • 多窗口/分屏模式:在多窗口模式下,窗口可能未获得焦点或处于非活跃状态,影响 SurfaceTexture 的创建。可以尝试在 onResume 或窗口获得焦点时再检查。
  • 同步模式:如果 SurfaceTexture 被设置为同步模式,onFrameAvailable 可能不会触发。检查是否有相关配置。
  • 延迟布局请求:有时 onSurfaceTextureAvailable 报告可用后,SurfaceTexture 可能瞬间不可用。一个可行的解决方法是延迟一小段时间后调用 requestLayout()

🛠️ 系统性排查步骤建议

可以按以下顺序快速定位问题:

  1. 检查硬件加速:确认 AndroidManifest.xml 和布局文件中没有禁用硬件加速。
  2. 检查可见性:确保设置监听器时 TextureViewVISIBLE 且有非零尺寸。
  3. 检查注册时机:确保监听器在 onCreate/onViewCreated 中尽早注册。
  4. 添加防御性检查:在设置监听器后,使用 if (textureView.isAvailable()) 手动调用回调逻辑。
  5. 检查视图层级:尝试将 TextureView 简化到最直接的布局中测试。
  6. 检查 SDK 配置:确认 build.gradleAndroidManifest.xml 中的 SDK 版本配置一致。

如果以上步骤都无法解决,可以检查 Logcat 中是否有来自 TextureViewSurfaceTexture 的警告或错误信息,这通常会提供更直接的线索。