SurfaceView 的渲染线程是否应与视图或活动具有相同的生命周期?



创建 SurfaceView 时,通常还会创建一个单独的线程来绘制到表面上。在活动的同时创建和销毁线程,还是同时创建和销毁表面,是更好的编程实践?

这两种方式的优点/陷阱是什么?

ActivityView基本上是同时创建的。Surface是稍后创建的,这就是SufaceHolder回调的用途。

您无法在Surface存在之前或销毁之后在它上渲染,因此在此之前启动渲染线程或让它在之后运行是没有意义的。 棘手的部分是回调发生在主 UI 线程上(因为这是您设置它的地方),因此可以在渲染线程工作时调用surfaceDestroyed()回调。

编辑:

下面包含有关 SurfaceView/活动生命周期的一些说明。 这些现在是官方 Android 文档的一部分;请参阅系统级图形文档中的附录 B。 原始帖子可在下面找到,用于历史目的。

您可以在 Grafika 中看到这两种方法的示例。 方法#1(在onResume/onPause中创建/销毁线程)可以在TextureFromCameraActivity中看到,方法#2(在surfaceCreated/surfaceDestroy中创建/销毁线程)可以在HardwareScalerActivity和RecordFBOActivity中看到。


关于应用程序生命周期和SurfaceView的一些想法。

有两件有点独立的事情正在发生:

  1. 应用程序创建/恢复/暂停
  2. 表面创建/更改/销毁

活动启动时,您会收到以下顺序的回调:

  • 创建
  • 在简历上
  • 曲面已创建
  • 表面已更改

如果您点击"返回",您将获得:

  • 暂停时
  • 表面
  • 已销毁(在表面消失之前调用)

如果您旋转屏幕,Activity将被拆除并重新创建,因此您可以获得 整个周期。 (您可以通过检查isFinishing()来判断这是"快速"重新启动。有可能如此快速地启动/停止一项活动,以至于surfaceCreated()可能会在onPause()之后发生,但我不确定。

但是,如果您点击电源按钮使屏幕空白,则只会得到onPause()- 没有surfaceDestroyed().Surface保持活动状态,渲染可以继续(您 如果您继续请求它们,甚至可以继续获得编舞活动)。 如果你有 强制特定方向的锁定屏幕可能会被踢Activity,但是 如果没有,你可以用你以前一样的Surface从屏幕空白出来。

当使用单独的渲染器线程时,这引发了一个基本问题SurfaceView:螺纹的寿命应该绑在Surface还是Activity? 答案是:这取决于您希望在屏幕时发生什么 变为空白。 有两种基本方法:(1) 在Activity上启动/停止线程 启动/停止;(2) 启动/停止线程Surface创建/销毁。

#1 与应用生命周期交互良好。 我们在onResume()中启动渲染器线程,然后 在onPause()停止它. 创建和配置线程时有点尴尬 因为有时 Surface 已经存在,有时不会。 我们不能简单地 将Surface回调转发到线程,因为如果Surface已经存在。 所以我们需要查询或缓存Surface状态,并转发它 到渲染器线程。 请注意,我们必须在这里小心地在传递对象之间 线程 - 最好通过Handler消息传递SurfaceSurfaceHolder,而不是 不仅仅是将其填充到线程中,以避免多核系统上出现问题(参见 安卓SMP入门)。

#2 具有一定的吸引力,因为Surface和渲染器在逻辑上是交织在一起的。 我们在创建Surface后启动线程,从而避免了线程间 沟通问题。Surface创建/更改的消息只需转发即可。 我们 需要确保渲染在屏幕变为空白时停止,并在屏幕变为空白时恢复 非空白;这可能是一个简单的问题,告诉编舞停止调用 帧绘制回调。 我们的onResume()将需要恢复回调,当且仅当 渲染器线程正在运行。 不过,这可能不是那么微不足道 - 如果我们基于动画 在帧之间经过的时间上,当下一个事件发生时,我们可能会有非常大的差距 到达,因此可能需要显式暂停/恢复消息。

以上主要关注渲染器线程的配置方式以及渲染器线程是否 它正在执行。 一个相关的问题是Activity被杀(onPause()onSaveInstanceState())。 方法#1将起作用最好这样做,因为一旦渲染器线程加入,其状态可以是 在没有同步基元的情况下访问。

最新更新