Android 防止 onPause 破坏 OpenGL 上下文
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/2112768/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Prevent onPause from trashing OpenGL Context
提问by cjserio
I'm writing an Android application that uses OpenGL ES (GLSurfaceView and GLSurfaceView.Renderer). The problem is that when the user switches applications and then switches back to my app, the GLSurfaceView destroys and recreates the GL context. This is what it's supposed to do according to the documentation but is there a way to prevent this from happening?
我正在编写一个使用 OpenGL ES(GLSurfaceView 和 GLSurfaceView.Renderer)的 Android 应用程序。问题是当用户切换应用程序然后切换回我的应用程序时,GLSurfaceView 会破坏并重新创建 GL 上下文。这是根据文档应该做的事情,但是有没有办法防止这种情况发生?
It takes a long time to load textures into the context and i'd like to prevent having to reload them.
将纹理加载到上下文中需要很长时间,我想避免重新加载它们。
采纳答案by seanhodges
I think what you are looking for is discussed in the GLSurfaceView documentation:
我认为您正在寻找的内容在 GLSurfaceView 文档中进行了讨论:
A GLSurfaceView must be notified when the activity is paused and resumed. GLSurfaceView clients are required to call onPause() when the activity pauses and onResume() when the activity resumes. These calls allow GLSurfaceView to pause and resume the rendering thread, and also allow GLSurfaceView to release and recreate the OpenGL display.
当活动暂停和恢复时,必须通知 GLSurfaceView。GLSurfaceView 客户端需要在活动暂停时调用 onPause(),在活动恢复时调用 onResume()。这些调用允许 GLSurfaceView 暂停和恢复渲染线程,还允许 GLSurfaceView 释放和重新创建 OpenGL 显示。
When using the standard Android SDK, you must release/recreate your context whenever the activity is paused/resumed (including screen orientation changes). Not doing so will cause the GL context to be release and not restored when the activity is loaded back into memory. Remember that we are dealing with very limited resources (particularly on low-spec devices). So the short answer is: you can't prevent it without breaking your app.
使用标准 Android SDK 时,您必须在 Activity 暂停/恢复时(包括屏幕方向更改)释放/重新创建上下文。不这样做将导致 GL 上下文被释放,并且在活动加载回内存时不会恢复。请记住,我们正在处理非常有限的资源(特别是在低规格设备上)。所以简短的回答是:你不能在不破坏你的应用程序的情况下阻止它。
Assuming you are using the standard Android/OpenGL framework, you need to do the following...
假设您使用的是标准的 Android/OpenGL 框架,您需要执行以下操作...
In your activity, ensure you have the following overridden methods:
在您的活动中,确保您拥有以下覆盖的方法:
public void onPause() {
myGlSurfaceView.onPause();
}
public void onResume() {
myGlSurfaceView.onResume();
}
Anything you hold outside the GL environment will still need to be preserved and restored manually however (bitmaps, game state, etc), for these you'll need to use static fields or a mechanism like SharedPreferences.
您在 GL 环境之外持有的任何内容仍然需要手动保存和恢复(位图、游戏状态等),对于这些,您需要使用静态字段或类似 SharedPreferences 的机制。
Update
更新
Android 3.x provides a function to preserve the GL context on pausewithout needing to be recreated. However, there are several caveats:
Android 3.x 提供了在暂停时保留 GL 上下文而无需重新创建的功能。但是,有几个注意事项:
- Android 3.x features are not available to approx. 90% of deviceson the market at this time
- The devices must also support multiple EGL contexts, it is unclear how many devices on the market currently support this.
Using some API reflection to check capabilities, it may be possible to make use of this function on supporting devices. However, you would still need to fall back to recreating the context for the rest. In my opinion, until more devices run Android 3 it would be better to hold off using setPreserveEGLContextOnPause
and focus on ensuring the context recreation approach is sufficiently tested.
使用一些 API 反射来检查功能,可能可以在支持的设备上使用此功能。但是,您仍然需要回退到为其余部分重新创建上下文。在我看来,在更多设备运行 Android 3 之前,最好暂缓使用setPreserveEGLContextOnPause
并专注于确保上下文娱乐方法得到充分测试。
回答by arberg
As mentioned in a comment above it is also possible to avoid trashing the GL context earlier Android releases (1.x, 2.x), the solution is to copy the GLSurfaceView from Android-15 SDK source code, change its package name, and then use your own copy of the GlSurfaceView.
正如上面的评论中提到的,也可以避免破坏早期 Android 版本(1.x、2.x)的 GL 上下文,解决方案是从 Android-15 SDK 源代码中复制 GLSurfaceView,更改其包名称,然后然后使用您自己的 GlSurfaceView 副本。
It should work for devices which support multiple GL contexts (except for Adreno chips, at the moment), regardless of Android version. A caveat is that GLSurfaceView from Android-15 only contains the necessary stuff to work with android-15, our version must handle all OS-versions.
它应该适用于支持多个 GL 上下文的设备(目前 Adreno 芯片除外),无论 Android 版本如何。需要注意的是,Android-15 中的 GLSurfaceView 仅包含与 android-15 配合使用的必要内容,我们的版本必须处理所有操作系统版本。
We use our own implemention of the GlSurfaceView based on a copy from ReplicaIsland, where Chriss Pruit also used his own implementation.
我们使用我们自己的基于 ReplicaIsland 副本的 GlSurfaceView 实现,其中 Chriss Pruit 也使用了他自己的实现。
In our version we added the setPreserveEGLContextOnPause from SDK-15, which allows to preserve GL context on for instance a nexus one running android 2.3.
在我们的版本中,我们添加了 SDK-15 中的 setPreserveEGLContextOnPause,它允许在运行 android 2.3 的节点上保留 GL 上下文。
We have also changed other stuff to suit our needs, which is not relevant for this question (such as 32-bit rendering on phones which support it, otherwise 16bit).
我们还更改了其他内容以满足我们的需求,这与此问题无关(例如支持它的手机上的 32 位渲染,否则为 16 位)。
Our GlSurfaceView: http://pastebin.com/U4x5JjAr
我们的 GlSurfaceView:http://pastebin.com/U4x5JjAr
Here is the original SDK-15 version of the GlSurfaceView formatted by same (Android) style as above http://pastebin.com/hziRmB3E(so that it is easy to compare and see the changes)
这是 GlSurfaceView 的原始 SDK-15 版本,格式与上述相同(Android)样式http://pastebin.com/hziRmB3E(以便于比较和查看更改)
Remember to enable the context preservation by calling:
请记住通过调用启用上下文保留:
glSurfaceView.setPreserveEGLContextOnPause(true);
回答by rockeye
Since API level 11, you can specify whether or not your context must be preserved.
从 API 级别 11 开始,您可以指定是否必须保留您的上下文。
From the doc :
从文档:
public void setPreserveEGLContextOnPause(boolean preserveOnPause) Since: API Level 11
Control whether the EGL context is preserved when the GLSurfaceView is paused and resumed.
If set to true, then the EGL context may be preserved when the GLSurfaceView is paused. Whether the EGL context is actually preserved or not depends upon whether the Android device that the program is running on can support an arbitrary number of EGL contexts or not. Devices that can only support a limited number of EGL contexts must release the EGL context in order to allow multiple applications to share the GPU.
If set to false, the EGL context will be released when the GLSurfaceView is paused, and recreated when the GLSurfaceView is resumed.
The default is false.
Parameters preserveOnPause preserve the EGL context when paused
public void setPreserveEGLContextOnPause(布尔值preserveOnPause)自:API 级别 11
控制在 GLSurfaceView 暂停和恢复时是否保留 EGL 上下文。
如果设置为 true,则在 GLSurfaceView 暂停时可以保留 EGL 上下文。EGL 上下文是否实际保留取决于运行程序的 Android 设备是否可以支持任意数量的 EGL 上下文。只能支持有限数量的 EGL 上下文的设备必须释放 EGL 上下文以允许多个应用程序共享 GPU。
如果设置为 false,则 EGL 上下文将在 GLSurfaceView 暂停时释放,并在 GLSurfaceView 恢复时重新创建。
默认值为假。
参数preserveOnPause 在暂停时保留EGL 上下文
回答by GenericMeatUnit
It's been a while since I worked with OpenGL and it was the standard sort on desktop pc's, but I seem to remember standard OpenGL doesn't require a reload of textures on context switch. Of course, that doesn't really help in this case.
自从我使用 OpenGL 以来已经有一段时间了,它是台式电脑上的标准类型,但我似乎记得标准 OpenGL 不需要在上下文切换时重新加载纹理。当然,这在这种情况下并没有真正的帮助。
Assuming the textures have to be reloaded, the question becomes: how do you speed this up? And then the question becomes, just how many textures do you need at any one time and can you load them on demand? What are their dimensions? I recall that powers of two were usually faster to load, though that may also depend on the OpenGL implementation and drivers.
假设必须重新加载纹理,问题就变成了:如何加快速度?然后问题就变成了,您在任何时候都需要多少纹理,并且您可以按需加载它们吗?它们的尺寸是多少?我记得 2 的幂通常加载速度更快,尽管这也可能取决于 OpenGL 实现和驱动程序。
I've also heard about keeping a context somewhere where it won't get destroyed, somewhat like this thread: opengles view switching problem
我也听说过将上下文保存在不会被破坏的地方,有点像这个线程:opengles view switch problem