Android 暂停时游戏状态发生变化

Android Game States Change when paused

以半传统方式,我有一个 activity 游戏 (MainActivity) 和一个表面视图 (MainSurface)。我设置了两个 "game states" 将它们自己渲染到表面视图 canvas(SplashState 和 ModelState)。

当应用程序启动时,表面视图将自身移交给启动状态,以便它可以像这样将自己绘制到屏幕上。

SurfaceHolder holder = getHolder();
        holder.addCallback(new SurfaceHolder.Callback() {
            @Override
            public void surfaceCreated(SurfaceHolder holder) {
                initInput();
                if(currentState == null){
                    setCurrentState(new SplashState());
                }
                initApp();
            @Override
            public void surfaceChanged(SurfaceHolder holder, int format, int         width, int height) {

            }

            @Override
            public void surfaceDestroyed(SurfaceHolder holder) {
                pauseApp();
            }
        });

private void pauseApp(){
        running = false;
        while(appThread.isAlive()){
            try{
                appThread.join();
                break;
            } catch (InterruptedException e){

            }
        }
    }

当用户触摸启动画面时,它会调用 SurfaceView 将状态更改为 ModelState(这是应用程序的主要状态)

@Override
    public boolean onTouch(MotionEvent e, int scaledX, int scaledY) {
        setCurrentState(new ModelState());
        return false;
   }

所有这一切都很棒。但是当我让我的设备休眠,或者使用另一个应用程序然后重新打开我的应用程序时,有时我会得到 ModelState,有时我会得到 SplashState。谁能解释为什么?我觉得我应该做更多的事情来保存应用程序暂停和恢复时的当前状态,这样它肯定会在同一个地方重新开始。任何帮助将不胜感激。

如果您只是想保存用户看到的状态(Model 或 Splash),您可以覆盖 onPause 和 onResume 来保存和检索状态。 OnPause 和 onResume 是应用程序进入后台时保证调用的仅有的两个方法,因此 saveInstanceState 和 restoreInstanceState 可能不适合您。

尝试使用 SharedPreferences 对象保存用户所处的状态。这是一个例子:

@Override
protected void onPause() {
    super.onPause();
    sharedPreferences = getSharedPreferences(KEY_SHARED_PREFERENCES, 0);
    SharedPreferences.Editor sharedPreferencesEditor = sharedPreferences.edit();

    sharedPreferencesEditor.putString(STATE_KEY, currentState);
    sharedPreferencesEditor.commit();
}

@Override
protected void onResume() {
    super.onResume();

    sharedPreferences.getString(MODEL_KEY, null)
}

该行为的部分原因与 SurfaceView 的工作方式有关。它的生命周期稍微独立于通常的 Activity 生命周期。

an appendix to the Graphics Architecture 文档中讨论了该现象。简而言之,系统试图避免破坏和重新创建表面。如果旋转设备,您会得到 pause/resume 和 destroy/create。如果您只是让设备进入休眠状态然后再将其唤醒,并且锁定屏幕不会强制旋转更改,您将得到 pause/resume 但不会得到 destroy/create.

诀窍是以适合决斗生命周期的方式管理渲染线程和资源分配(尤其是打开和关闭相机之类的东西)。

There are two basic approaches: (1) start/stop the thread on Activity start/stop; (2) start/stop the thread on Surface create/destroy.

该文档继续解释了其中每一个的含义,以及何时必须采取相关的其他操作。 Grafika 中可以找到这两种方法的示例; "texture from camera" activity 使用#1,而 "hardware scaler exerciser" activity 使用#2.

回到您的代码,您正在从 surfaceDestroyed() 调用 pauseApp()。由于无法保证表面会被破坏,因此当应用程序暂停时,您的 pauseApp() 代码可能不会 运行。向各种状态更改功能添加一些日志记录,并在您导航设备时观察它们在 logcat 中触发(或不触发)。