源码分析 | ThreadedRenderer 空指针问题,顺便把 Choreographer 认识一下
2024-02-04 00:02:16
ThreadedRenderer 空指针异常:深入浅出的分析与解决方案
在 Android 开发的浩瀚世界中,开发者时常会遇到各种各样的问题和异常,其中之一便是令人生畏的 ThreadedRenderer 空指针异常。本次,我们将踏上一次探索之旅,深入了解 ThreadedRenderer 的工作原理,分析异常背后的根源,并探讨切实可行的解决方案。
什么是 ThreadedRenderer?
ThreadedRenderer 是 Android 框架中一个至关重要的组件,负责在独立的工作线程上执行 OpenGL ES 绘制任务。其采用了双缓冲技术,即在工作线程上渲染一帧,而在主线程上显示另一帧。
ThreadedRenderer 的运作方式如下:
- SurfaceTexture 的创建与传递: 主线程创建一个 SurfaceTexture 对象并将其传递给 ThreadedRenderer。
- EGLSurface 的创建与附加: ThreadedRenderer 创建一个 EGLSurface 并将其附加到 SurfaceTexture 上。
- OpenGL 上下文的创建与渲染: ThreadedRenderer 在工作线程上创建 OpenGL 上下文并开始渲染。
- 帧的提交与显示: 渲染完成一帧后,ThreadedRenderer 将其提交给 SurfaceFlinger,后者负责在屏幕上显示该帧。
- 渲染结果的获取: 主线程通过 SurfaceTexture 从 ThreadedRenderer 获取渲染结果。
ThreadedRenderer 空指针异常的成因
根据本文开头提到的异常堆栈,问题根源在于 ThreadedRenderer 试图将一个空 SurfaceTexture 对象附加到 EGLSurface。这表明在传递给 ThreadedRenderer 之前,SurfaceTexture 对象已经遭到销毁。
问题的解决方案
为了解决这一问题,我们需要找出导致 SurfaceTexture 对象被销毁的原因。经调查,发现销毁操作发生在 onPause() 方法中,如下所示:
@Override
protected void onPause() {
super.onPause();
// 销毁 SurfaceTexture 对象
mSurfaceTexture.release();
}
在 onPause() 方法中销毁 SurfaceTexture 是不恰当的,因为它将导致 ThreadedRenderer 在附加 SurfaceTexture 对象到 EGLSurface 时遭遇空指针异常。
正确的做法是在 onDestroy() 方法中销毁 SurfaceTexture 对象,如下所示:
@Override
protected void onDestroy() {
super.onDestroy();
// 销毁 SurfaceTexture 对象
mSurfaceTexture.release();
}
Choreographer:主线程与工作线程的协作
在分析 ThreadedRenderer 空指针问题时,我们还遇到了另一个重要组件:Choreographer。Choreographer 负责协调主线程和工作线程之间的通信,并利用 VSYNC 信号同步两者的动作。
当 VSYNC 信号到来时,Choreographer 会触发 Choreographer.FrameCallback,该回调可以在主线程或工作线程上执行。
在我们的案例中,ThreadedRenderer 使用 Choreographer 同步其渲染任务。当 VSYNC 信号到达时,Choreographer 会触发 ThreadedRenderer 的 draw() 方法,后者在工作线程上执行。
总结
通过对 ThreadedRenderer 空指针问题的深入分析,我们不仅了解了 ThreadedRenderer 的工作原理,还领悟了 Choreographer 在 Android 系统中的重要作用。我们还探索了导致 SurfaceTexture 对象被销毁的根源,并找到了切实可行的解决方案。
通过这趟分析之旅,我们再次体会到扎实的基础知识和细致的排查过程对解决 Android 开发问题至关重要。希望本次分享能为开发者们提供有益的参考,助力大家攻克更多技术难关!
常见问题解答
-
ThreadedRenderer 适用于哪些场景?
ThreadedRenderer 适用于需要在独立线程上进行 OpenGL ES 绘制任务的场景,例如游戏、3D 渲染和视频播放。 -
如何避免在 onPause() 方法中销毁 SurfaceTexture 对象?
正确的做法是在 onDestroy() 方法中销毁 SurfaceTexture 对象,以确保在 ThreadedRenderer 完成渲染任务后才执行销毁操作。 -
Choreographer 的作用是什么?
Choreographer 协调主线程和工作线程之间的通信,并使用 VSYNC 信号同步两者的动作,以确保流畅的视觉体验。 -
如何使用 Choreographer 同步渲染任务?
可以通过实现 Choreographer.FrameCallback 接口并注册监听器的方式,在 VSYNC 信号到来时执行渲染任务。 -
解决 ThreadedRenderer 空指针异常有哪些其他技巧?
除了本文提到的解决方案外,还可尝试检查 SurfaceTexture 对象是否在多个线程中使用,以及是否在 ThreadedRenderer 使用 SurfaceTexture 对象之前及时创建和附加 EGLSurface。