Android:Activity和Renderer之间的内存优化通信(GLSurfaceView)

时间:2015-12-15 15:09:40

标签: android multithreading android-activity opengl-es glsurfaceview

我目前正在开发Android游戏,并遇到有关Activity和Renderer之间通信的问题。

场景

我有ActivityGLSurfaceView作为内容视图,Renderer附加到GLSurfaceViewRenderer包含游戏循环。它绘制场景并更新游戏状态。这似乎是最好的做法,到目前为止工作顺利。 Activity还会显示按钮或游戏分数等UI元素。

Activity在UI线程中运行,Renderer有自己的线程。所以基本上我必须处理线程间通信。我使用GLSurfaceView.queueEvent(Runnable)Renderer调用Activity帖子中的内容(例如,开始游戏循环)。要从Renderer中使用Activity.runOnUiThread(Runnable)来调用UI线程中的内容(例如更新游戏分数UI元素)。

问题

每次我想与其他线程通信时,必须实例化Runnable。在某些时候,这将触发垃圾收集,因为VM需要释放内存。这当然会打断游戏。

问题

在没有实例化新对象的情况下还有其他选择吗?目标是在游戏运行时保持内存分配不变。

2 个答案:

答案 0 :(得分:2)

不要为每条消息分配Runnables。为接收消息的线程创建一个处理程序,并获取带有例如消息的消息对象。 obtainMessage()以避免分配。

您可以在Grafika中找到多个此示例,其中包含最小化或消除各种活动分配的步骤。 Android Breakout在游戏过程中没有[*]分配(虽然它在播放时不使用任何View UI)。

切换到本机代码的建议通常是过度的,特别是如果您的唯一目的是避免垃圾回收。

评估游戏状态的最佳工具是DDMS allocation tracker,它显示了N个最近的分配。

[*]我有一段时间没有检查Android Breakout。目标是零分配。

答案 1 :(得分:1)

我不会将Android UI元素与GLSurfaceView混合使用。为什么,你可能会问。好吧,普通的UI元素使用OGL作为尽力而为。如果某些事情无法使用OGL呈现,则会以其他方式呈现它们(例如,软件渲染)。此外,渲染这些元素受Activity活动渲染循环的生命周期影响,从而有效地限制了游戏的性能。

如果您希望最小化GC运行/ queueEvent来电,可以执行某些操作。

Go native

在C ++中,您可以随意分配自己的东西并随意释放它们。本机代码通常用于游戏物理和类似的东西,但你也可以将OpenGL放入其中。

更改模型

就像我说的那样,我不会使用普通的UI元素,而是使用OGL中的纹理(精灵)来渲染我自己的元素,从而消除了runOnUiThread的需要。

对于queueEvent,只有在您调用的代码修改OGL状态机时才需要(基本上所有gl*调用)。我的猜测是你主要使用这个事件排队将触摸坐标和其他“修饰符”传递给你的游戏逻辑。为了摆脱这种情况,不要直接从调用的方法修改OGL,只需更改模型属性并在下一个渲染循环中绘制/设置新的OGL状态(确保以同步方式进行更改,否则它可以搞乱事情。)

完全使用Canvas而不是OpenGL

如果您的游戏图形不重并且不需要特殊渲染选项,则可以使用自定义View的画布,这样您也可以渲染文本。请注意,画布最终可能会使用OGL来处理很多事情,所以对于创建休闲2D游戏,它仍然很好。

请记住......

使用新的queueEvent实例调用Runnable并不一定是件坏事。运行Runnable实例的GLThread在从队列中取出并运行后将其置零(将其设置为null),这告诉GC它可以随时释放其内存。这是一种在Java编程中广泛使用的优化技术,因为GC不再需要测试关于此对象的某些内容。因此,GC运行不会花费你想象的那么多时间。