这两种方式有哪些优点/缺陷?
解决方法
你不能在Surface存在之前或者在它被破坏之后在Surface上渲染,所以在此之前启动你的渲染线程或让它继续运行是没有意义的.棘手的部分是回调发生在主UI线程上(因为那是你设置它的地方),因此可以在渲染线程正在工作时调用surfaceDestroyed()回调.
编辑:
下面列出了有关SurfaceView / Activity生命周期的一些注意事项.这些现在是官方Android文档的一部分;请参阅System-Level Graphics doc中的附录B.出于历史目的,下面提供了原始帖子.
您可以在Grafika中看到这两种方法的示例.方法#1(在onResume / onPause中创建/销毁线程)可以在TextureFromCameraActivity中看到,方法#2(在surfaceCreated / surfaceDestroyed中创建/销毁线程)可以在HardwareScalerActivity和RecordFBOActivity中看到.
关于应用程序生命周期和SurfaceView的一些想法.
有两个独立的事情在发生:
>应用onCreate / onResume / onPause
>表面创建/更改/销毁
当Activity开始时,您将按以下顺序获得回调:
> onCreate
> onResume
> surfaceCreated
> surfaceChanged
如果你点击“返回”,你会得到:
> onPause
> surfaceDestroyed(在Surface消失之前调用)
如果您旋转屏幕,活动将被拆除并重新创建,以便您获得
整个周期. (你可以通过检查isFinishing()来判断它是“快速”重启.)有可能在onPause()之后如此快地启动/停止一个活动,但是我不确定.
但是,如果点击电源按钮使屏幕空白,则只能使用onPause() –
没有surfaceDestroyed(). Surface保持活着,渲染可以继续(你
如果你继续请求它们,甚至会继续得到Choreographer事件).如果你有
一个锁定屏幕,强制您的活动可以被踢的特定方向,但是
如果没有,你可以使用与之前相同的Surface屏幕空白.
当使用单独的渲染器线程时,这引发了一个基本问题
SurfaceView:应该将线程的生命周期绑定到Surface或者
活动?答案是:它取决于你想在屏幕上发生什么
空白.有两种基本方法:(1)在Activity上启动/停止线程
启动/停止; (2)启动/停止Surface创建/销毁线程.
#1与应用程序生命周期很好地交互.我们在onResume()和中启动渲染器线程
在onPause()中停止它.在创建和配置线程时,它有点尴尬
因为有时Surface已经存在,有时它不会存在.我们不能简单
将Surface回调转发给线程,因为如果它们不会再次触发
表面已经存在.所以我们需要查询或缓存Surface状态,然后转发它
到渲染器线程.注意我们在这里传递对象时必须要小心
线程 – 最好通过Handler消息传递Surface或SurfaceHolder
而不仅仅是填充到线程中,以避免多核系统出现问题(参见
Android SMP Primer).
#2具有一定的吸引力,因为Surface和渲染器在逻辑上交织在一起.
我们在创建Surface之后启动线程,这避免了线程间
沟通问题.表面创建/更改的消息只是转发.我们
当屏幕变为空白时,需要确保渲染停止,并在屏幕空白时恢复
取消毛坯;这可能是一个简单的问题,告诉编舞者停止调用
框架绘制回调.我们的onResume()将需要恢复回调,当且仅当
渲染器线程正在运行.它可能不是那么微不足道 – 如果我们以动画为基础
在帧之间经过的时间,我们在下一个事件时可能会有很大的差距
到达时,可能需要明确的暂停/恢复消息.
以上主要涉及渲染器线程的配置方式以及是否它正在执行.一个相关的问题是当线程从线程中提取状态活动被终止(在onPause()或onSaveInstanceState()中).方法#1将起作用最好的,因为一旦渲染器线程已加入其状态即可没有同步原语访问.