1)如果您想在加载资源时显示启动画面,您应该在后台线程上进行尽可能多的加载。这是一个很好的做法,释放 GL 线程来做任何你想做的事情,因为它不忙于加载资源。但是,任何与 OpenGL 的直接交互都需要在 GL 线程上完成,例如上传纹理或编译着色器。
通常,您将使用AsyncTask
需要与 UI 线程交互的后台资源加载。但是,GLSurfaceView
不使用 GL 的主 UI 线程,因此AsyncTask
不会在这里工作。不过,我们可以很容易地通过其他方式获得类似的行为。只需在您自己的后台线程上加载您的资源代码并将结果发布到 GL 线程上,使用GLSurface.queueEvent()
. 后台资源加载可以通过多种方式完成;在这个例子中,让我们使用一个带有单个后台线程的 Executor。一切都已加载onSurfaceChanged()
,确保在用户暂停/停止并启动/恢复应用程序时再次重新创建它:
private Executor mExecutor = Executors.newSingleThreadExecutor();
@Override
public void onSurfaceChanged(final int width, final int height) {
// Let's define a few states for the application; NONE, SPLASH,
// GAME.
mRenderState = NONE;
// Currently, the screen is black. Let's get something on screen as
// quickly as possible. Create a thread and start loading resources.
mExecutor.execute(new Runnable() {
@Override
public void run() {
final Resources res = mContext.getResources();
// Load splash screen resource on background thread.
final Bitmap splashBitmap = BitmapFactory.decodeResource(res, R.drawable.splash);
// Splash screen is loaded, post a Runnable that will run on the GL thread.
mGLSurfaceView.queueEvent(new Runnable() {
@Override
public void run() {
// Upload splash texture to GL, on GL thread.
GLUtils.texImage2D(GLES10.GL_TEXTURE_2D, 0, splashBitmap, 0);
// Recycle bitmap. We'll create a lot of bitmaps during loading.
// Each bitmap is only needed until we have uploaded it to GL. After
// that it's just wasting memory. Especially on older phones.
splashBitmap.recycle();
// Notify application that the splash screen is loaded,
// and it's okay to render it.
mRenderState = SPLASH;
// Screen is no longer black. User sees a splash screen,
// perhaps with a progress bar or a nice animation.
// Start loading the other textures.
// ...
// Texture loading finished.
mRenderState = GAME;
}
});
}
});
}
@Override
public void onDrawFrame()
{
if (mRenderState == SPLASH) {
// Render splash screen and a progress bar.
} else if (mRenderState == GAME) {
// Render game.
}
}
2)您可以测量加载启动画面所需的时间,并在快速设备和慢速设备上进行比较。如果它的加载速度与快速设备一样快,只需不要将 mRenderState 设置为 SPLASH,用户将继续看到黑屏。希望黑屏能在不到一秒的时间内被游戏取代。如果需要,可以在加载资源时添加更多时间,如果时间过长,请启用 SPLASH 渲染状态。
此外,淡入和淡出启动屏幕可能会惹恼用户,而不仅仅是将其弹出和弹出视图。
3)有几件事可能导致口吃,但我会在放弃之前至少检查这些:
a)内存管理。Android 限制了每个进程的内存堆大小,旧设备每个进程的堆内存比新设备少得多,例如 16-32 MB 和 128 MB。这意味着垃圾收集器将在旧设备上做更多的工作,当您加载许多繁重的资源时。在“logcat”中查找很多这样的消息:
D/dalvikvm: GC_CONCURRENT freed 4027K, 30% free 29173K/41635K, paused 3ms+8ms
这些可能只是您之前加载的位图被冲出内存,或者您正在创建许多其他对象来触发旧设备上的 GC。希望通过在加载时回收位图来缓解这种情况。
b)只需检查其他进程是否占用 CPU,使用:
adb shell top -m 10
这将显示前 10 个进程的 CPU 使用率。
c)从“DDMS”运行方法分析。在游戏卡顿时,按下“设备”选项卡上带有三个箭头和一个红色圆圈的小按钮。几秒钟后再次按下它以获得分析结果。学习如何阅读图表需要一些时间,但它基本上会告诉您应用程序的哪些部分当前正在使用 CPU。也许前 10 秒有些东西在努力工作。将其与一切运行顺利的分析结果进行比较。