运行 glThread 上的长任务不会阻塞 UI Android 上的线程
Run long task on glThread without blocking UI thread on Android
我必须 运行 通过大量初始化才能在 GLSurfaceView
中渲染任何内容
这些必须在 OpenGL 线程上完成。
然而,这会在初始化期间挂起我的主线程。
这是我的代码:
@Override
protected void onStart() {
super.onStart();
FrameLayout renderingLayout = (FrameLayout) findViewById(R.id.movie_rendering_layout);
if (renderingLayout != null && mGLView == null) {
mGLView = new MyGLSurfaceView(getApplicationContext());
/** [..] **/
renderingLayout.addView(mGLView, params);
}
}
/*--------------- OPENGL RELATED ---------------*/
protected class MyGLSurfaceView extends GLSurfaceView {
private final MyGLRenderer mRenderer;
public MyGLSurfaceView(Context context) {
super(context);
// Create an OpenGL ES 1.0 context
setEGLContextClientVersion(1);
mRenderer = new MyGLRenderer();
// Set the Renderer for drawing on the GLSurfaceView
setRenderer(mRenderer);
}
}
protected class MyGLRenderer implements GLSurfaceView.Renderer {
private int mWidth, mHeight = 0;
private boolean isFinished = false;
public void onSurfaceCreated(GL10 unused, EGLConfig config) {
// Set the background frame color
GLES10.glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
init(mMovieIndex, AssetsUtils.getBinPath(getApplicationContext())); // <----- THIS takes long time
}
public void onDrawFrame(GL10 pGL10) {
GLES10.glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
GLES10.glClear(GLES10.GL_COLOR_BUFFER_BIT);
/* [...] */
}
我找到了解决方案:
问题是您不能在 onDrawFrame
或 onSurfaceCreated
中阻塞,因为它们由主线程同步调用。
为了禁用调用,我在表面构造函数中使用了:
setRenderMode(RENDERMODE_WHEN_DIRTY);
这样,一旦视图确定,对 onDrawFrame
的调用就会停止。
我从
执行了初始化
public void onWindowFocusChanged(boolean hasFocus)
小心它会被调用两次。如果有人有更好的建议我很乐意听取(摘自How to make a callback after the view is completely rendered?)
我也覆盖了
@Override
public boolean isDirty()
return false;
}
不要忘记在 GLThread
上使用 queueEvent
到 运行 代码
通常的答案是在同一个共享组中创建两个 EGL 上下文,每个都绑定到一个单独的线程。
渲染循环中的主线程对屏幕进行任何渲染,这在资源加载期间通常是一些东西 "boring" - 即加载图形、进度条等。
第二个线程在后台加载任何批量资源,例如加载纹理文件、模型网格等并上传它们。
加载完成后,主线程可以使用辅助异步加载线程加载的所有数据资源。
我必须 运行 通过大量初始化才能在 GLSurfaceView
这些必须在 OpenGL 线程上完成。
然而,这会在初始化期间挂起我的主线程。
这是我的代码:
@Override
protected void onStart() {
super.onStart();
FrameLayout renderingLayout = (FrameLayout) findViewById(R.id.movie_rendering_layout);
if (renderingLayout != null && mGLView == null) {
mGLView = new MyGLSurfaceView(getApplicationContext());
/** [..] **/
renderingLayout.addView(mGLView, params);
}
}
/*--------------- OPENGL RELATED ---------------*/
protected class MyGLSurfaceView extends GLSurfaceView {
private final MyGLRenderer mRenderer;
public MyGLSurfaceView(Context context) {
super(context);
// Create an OpenGL ES 1.0 context
setEGLContextClientVersion(1);
mRenderer = new MyGLRenderer();
// Set the Renderer for drawing on the GLSurfaceView
setRenderer(mRenderer);
}
}
protected class MyGLRenderer implements GLSurfaceView.Renderer {
private int mWidth, mHeight = 0;
private boolean isFinished = false;
public void onSurfaceCreated(GL10 unused, EGLConfig config) {
// Set the background frame color
GLES10.glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
init(mMovieIndex, AssetsUtils.getBinPath(getApplicationContext())); // <----- THIS takes long time
}
public void onDrawFrame(GL10 pGL10) {
GLES10.glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
GLES10.glClear(GLES10.GL_COLOR_BUFFER_BIT);
/* [...] */
}
我找到了解决方案:
问题是您不能在 onDrawFrame
或 onSurfaceCreated
中阻塞,因为它们由主线程同步调用。
为了禁用调用,我在表面构造函数中使用了:
setRenderMode(RENDERMODE_WHEN_DIRTY);
这样,一旦视图确定,对 onDrawFrame
的调用就会停止。
我从
执行了初始化public void onWindowFocusChanged(boolean hasFocus)
小心它会被调用两次。如果有人有更好的建议我很乐意听取(摘自How to make a callback after the view is completely rendered?)
我也覆盖了
@Override
public boolean isDirty()
return false;
}
不要忘记在 GLThread
上使用queueEvent
到 运行 代码
通常的答案是在同一个共享组中创建两个 EGL 上下文,每个都绑定到一个单独的线程。
渲染循环中的主线程对屏幕进行任何渲染,这在资源加载期间通常是一些东西 "boring" - 即加载图形、进度条等。
第二个线程在后台加载任何批量资源,例如加载纹理文件、模型网格等并上传它们。
加载完成后,主线程可以使用辅助异步加载线程加载的所有数据资源。