SurfaceView的renderingThread是否与视图或活动具有相同的生命周期?

GDa*_*ger 6 android design-patterns surfaceview

在创建SurfaceView时,通常还要创建一个单独的线程来绘制到曲面上.是否更好的编程实践是在活动同时创建和销毁线程,或者同时表面是什么?

这两种方式有哪些优点/缺陷?

fad*_*den 13

ActivityView在基本上相同的时间创建.在Surface随后建立,而这正是该SufaceHolder回调是.

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

编辑:

下面列出了有关SurfaceView/Activity生命周期的一些注意事项.这些现在是官方Android文档的一部分; 请参阅系统级图形文档中的附录B. 出于历史目的,下面提供了原始帖子.

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


关于应用生命周期和应用的一些想法SurfaceView.

有两个独立的事情在发生:

  1. 应用onCreate/onResume/onPause
  2. 表面创建/更改/销毁

当Activity开始时,您将按以下顺序获得回调:

  • 的onCreate
  • 的onResume
  • surfaceCreated
  • surfaceChanged

如果你点击"返回",你会得到:

  • 在onPause
  • surfaceDestroyed(在Surface消失之前调用)

如果旋转屏幕,Activity则会将其拆除并重新创建,以便获得完整的循环.(您可以通过检查来判断它是"快速"重启isFinishing().)可能会很快启动/停止活动,但surfaceCreated()可能会发生onPause(),但我不确定.

但是,如果点击电源按钮使屏幕空白,则只能获得onPause()- 否surfaceDestroyed().该Surface遗骸活着,渲染可以继续(你甚至不断收到编舞的事件,如果你继续要求他们).如果你有一个锁定屏幕强制一个特定的方向你Activity可以被踢,但如果没有你可以用Surface你以前的屏幕空白.

当使用单独的渲染器线程时,这会引发一个基本问题 SurfaceView:是否应该将线程的生命周期SurfaceActivity?或 ?答案是:它取决于屏幕空白时您想要发生什么.有两种基本方法:(1)启动/停止启动/停止线程Activity ; (2)在Surfacecreate/destroy 上启动/停止线程.

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

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

以上主要涉及渲染器线程的配置方式以及是否正在执行.一个相关的问题是当被杀死时(在或中)线程中 提取状态.方法#1最适合这种方法,因为一旦渲染了渲染器线程,就可以在没有同步原语的情况下访问它的状态.ActivityonPause()onSaveInstanceState()