【发布时间】:2014-02-05 02:42:04
【问题描述】:
创建 SurfaceView 时,通常还会创建一个单独的线程来绘制到表面上。在活动的同时创建和销毁线程是更好的编程实践,还是在表面的同时创建和销毁?
这两种方式都有哪些优点/缺点?
【问题讨论】:
标签: android design-patterns surfaceview
创建 SurfaceView 时,通常还会创建一个单独的线程来绘制到表面上。在活动的同时创建和销毁线程是更好的编程实践,还是在表面的同时创建和销毁?
这两种方式都有哪些优点/缺点?
【问题讨论】:
标签: android design-patterns surfaceview
Activity 和View 基本上是同时创建的。 Surface 是稍后创建的,这就是 SufaceHolder callbacks 的用途。
您无法在 Surface 存在之前或被销毁之后对其进行渲染,因此在此之前启动渲染线程或让它继续运行是没有意义的。棘手的部分是回调发生在主 UI 线程上(因为这是您设置它的地方),因此可以在渲染线程工作时调用 surfaceDestroyed() 回调。
编辑:
关于 SurfaceView / Activity 生命周期的一些注释包括在下面。这些现在是官方 Android 文档的一部分;请参阅System-Level Graphics 文档中的附录 B。原始帖子可用于历史目的。
您可以在Grafika 中查看这两种方法的示例。方法一(在 onResume/onPause 中创建/销毁线程)可以在TextureFromCameraActivity 中看到,方法二(在surfaceCreated/surfaceDestroyed 中创建/销毁线程)可以在HardwareScalerActivity 和RecordFBOActivity 中看到。
SurfaceView 的一些想法。
有两件有些独立的事情正在发生:
当 Activity 启动时,你会按以下顺序获得回调:
如果你点击“返回”,你会得到:
如果您旋转屏幕,Activity 会被拆除并重新创建,因此您会得到
整个周期。 (您可以通过检查 isFinishing() 来判断这是“快速”重启。)可能可以如此快速地启动/停止活动,以至于 surfaceCreated() 可能会在 onPause() 之后发生,但我'我不确定。
然而,如果你点击电源按钮来黑屏,你只会得到onPause() --
没有surfaceDestroyed()。 Surface 仍然存在,渲染可以继续(你
如果您继续请求它们,甚至会继续获取 Choreographer 事件)。如果你有
锁定屏幕,强制您的Activity 可以被踢出特定的方向,但是
如果没有,您可以使用与以前相同的Surface 退出屏幕空白。
当使用单独的渲染器线程时,这会引发一个基本问题
SurfaceView:线程的生命周期是否应该与Surface 或
Activity?答案是:这取决于你想在屏幕上发生什么
变为空白。有两种基本方法:(1)在Activity上启动/停止线程
开始/停止; (2) 在Surface create/destroy 上启动/停止线程。
#1 与应用生命周期很好地交互。我们在onResume() 中启动渲染器线程,然后
停止它在onPause()。创建和配置线程时有点尴尬
因为有时 Surface 已经存在,有时则不存在。我们不能简单
将Surface 回调转发给线程,因为如果
Surface 已经存在。所以我们需要查询或缓存Surface状态,并转发
到渲染器线程。注意我们在这里传递对象时要小心一点
线程——最好通过Handler消息传递Surface或SurfaceHolder,而不是
不仅仅是将其塞入线程中,以避免多核系统上的问题(cf.
Android SMP Primer)。
#2 有一定的吸引力,因为Surface 和渲染器在逻辑上是交织在一起的。
我们在Surface创建后启动线程,避免了线程间
沟通问题。 Surface 创建/更改的消息只是转发。我们
需要确保渲染在屏幕变黑时停止,并在它出现时恢复
非空白;这可能是告诉 Choreographer 停止调用
帧绘制回调。当且仅当我们的onResume() 需要恢复回调
渲染器线程正在运行。但它可能不是那么微不足道——如果我们基于动画
在帧之间经过的时间上,当下一个事件发生时,我们可能会有一个 非常 大的差距
到达,因此可能需要明确的暂停/恢复消息。
上面主要关心渲染器线程是如何配置的,是否
它正在执行。一个相关的问题是从线程中提取状态,当
Activity 被杀死(在 onPause() 或 onSaveInstanceState() 中)。方法 #1 会奏效
最好的,因为一旦渲染器线程被加入,它的状态就可以
无需同步原语即可访问。
【讨论】:
onSaveInstanceState 或 onRestoreInstanceState 时线程/表面将有效。