【问题标题】:Strange occurence when passing values to bundle将值传递给捆绑时出现奇怪的情况
【发布时间】:2011-10-23 07:41:08
【问题描述】:

我正在使用 onSaveInstanceState 和 onRestoreInstanceState 在我的游戏进入后台后保存我的关卡数据。一切似乎都很好,但是当您使用电源按钮锁定手机时,我遇到了一个一致的问题。除了调用保存之外,我还同时接到了一个恢复电话,然后又接到了另一个电话来保存,然后当我再次解锁手机时,我又接到了另一个电话来保存,最后又接到了另一个电话来恢复。我已经使用日志标签检查了我的值,并且我的 ArrayList 第一次返回为空是在我锁定手机后第二次调用保存之后。这是我的堆栈跟踪:

//Locks Phone
10-23 08:34:03.797: DEBUG/input(6535): saveLevel[001, 001, 001, 001, 001, 001, 001, 000, 000, 000, 000, 001, 000, 001, 001, 001, 001, 000, 000, 000, 000, 000, 000, 000, 001, 001, 001, 001, 001, 001, 000, 000, 000, 001, 000, 001, 001, 001, 001, 001, 001, 001, 000, 000, 000, 000, 000, 000, 000, 000, 000, 000, 000, 000]
10-23 08:34:04.813: DEBUG/input(6535): RestoredLevel[001, 001, 001, 001, 001, 001, 001, 000, 000, 000, 000, 001, 000, 001, 001, 001, 001, 000, 000, 000, 000, 000, 000, 000, 001, 001, 001, 001, 001, 001, 000, 000, 000, 001, 000, 001, 001, 001, 001, 001, 001, 001, 000, 000, 000, 000, 000, 000, 000, 000, 000, 000, 000, 000]
10-23 08:34:05.602: DEBUG/input(6535): saveLevel[]

//Unlocks Phone
10-23 08:34:14.656: DEBUG/input(6535): saveLevel[]
10-23 08:34:14.836: DEBUG/input(6535): RestoredLevel[]

当我以其他方式退出应用程序时,不会发生同样的事情。

这是我的 onSave 和 OnRestore 方法:

 @Override
protected void onSaveInstanceState(Bundle outState){
    super.onSaveInstanceState(outState);
    levelDat = CSVReader.getleveldat(); //CSVReader is the class that creates the    ArrayList 
    outState.putStringArrayList("LEVELDATA", levelDat);
    Log.d(TAG, "saveLevel" + String.valueOf(levelDat));
}

@Override
protected void onRestoreInstanceState(Bundle savedInstanceState){
    super.onRestoreInstanceState(savedInstanceState);
    levelDat = savedInstanceState.getStringArrayList("LEVELDATA");
    MRenderer.recoverLevel(); // just a method to force update my level data in my renderer.
    Log.d(TAG, "RestoredLevel" + String.valueOf(levelDat));
}

有没有办法阻止这种情况发生,如果没有,我可以提供一些提示来帮助我让我的代码识别丢失的数据并重新读取 CSV 文件。

【问题讨论】:

    标签: android opengl-es arraylist save restore


    【解决方案1】:

    在这篇文章 (http://ogrelab.ikratko.com/activity-lifecycle-explained-in-details/) 中有一个示例项目,它通过 logcat 生命周期事件以及调用的时间和方法进行演示。长话短说:您需要在onCreate() 中恢复您的状态,而不是在onRestoreInstanceState() 中。

    以下是手机锁定时的日志示例:

    10-23 10:50:20.847: I/TEST(913): A onSaveInstanceState
    10-23 10:50:20.847: I/TEST(913): A onPause
    10-23 10:50:20.847: I/TEST(913): A onStop
    10-23 10:50:20.847: I/TEST(913): A onDestroy | isFinishing: false
    10-23 10:50:20.859: I/TEST(913): A onCreate
    10-23 10:50:20.859: I/TEST(913): A onStart
    10-23 10:50:20.859: I/TEST(913): A onRestoreInstanceState
    10-23 10:50:20.863: I/TEST(913): A onResume
    10-23 10:50:21.210: I/TEST(913): A onSaveInstanceState
    10-23 10:50:21.210: I/TEST(913): A onPause
    

    如您所见,在调用 onSaveInstanceState() 之后,您的活动被杀死,然后再次创建,因为您错过了在 onCreate() 中恢复您的状态,您的 ArrayList 为空。

    一般来说,onRestoreInstanceState() 用于特殊情况,当一些花哨/奇怪的 UI 需要非标准恢复其状态时。

    【讨论】:

    • 是否可以将我的恢复方法中的levelDat = savedInstanceState.getStringArrayList("LEVELDATA"); 行直接放入onCreate 中?
    • 哦,在手机锁定或一段时间后立即调用 onDestroy。
    • 是的,您可以将levelDat = ... 移动到onCreate()。
    • 至少 pn 我的手机 (Galaxy S),onDestroy() 在锁定后立即被调用。
    • 如果我没有实现 onDestroy 会不会被调用?听起来不太可能。顺便说一句,我在 2.2 atm 上运行。
    【解决方案2】:

    这有点像在黑暗中拍摄,但第二次保存可能无法找到数据,因为它在恢复后调用得太快了。我会猜到这些方法在同一个线程上运行,但我会尝试在数据对象上同步,看看它是否真的是一个竞争条件。

    @Override
    protected void onSaveInstanceState(Bundle outState) {
        synchronized(levelDat) {
            super.onSaveInstanceState(outState);
            levelDat = CSVReader.getleveldat(); //CSVReader is the class that creates the    ArrayList 
            outState.putStringArrayList("LEVELDATA", levelDat);
            Log.d(TAG, "saveLevel" + String.valueOf(levelDat));
        }
    }
    
    @Override
    protected void onRestoreInstanceState(Bundle savedInstanceState) {
        synchonized(levelDat) {
            super.onRestoreInstanceState(savedInstanceState);
            levelDat = savedInstanceState.getStringArrayList("LEVELDATA");
            MRenderer.recoverLevel(); // just a method to force update my level data in my renderer.
            Log.d(TAG, "RestoredLevel" + String.valueOf(levelDat));
        }
    }
    

    【讨论】:

    • 感谢您的快速回答,但我已经解决了问题。我所要做的就是确保 CSVReader 类中的 ArrayList 在恢复时是最新的(因为这是渲染器最初获取关卡数据的地方),并确保与 ArrayList 相关的任何变量都已更新(例如:我有大小存储在某个变量中的arrayList)
    猜你喜欢
    • 1970-01-01
    • 2015-09-20
    • 2016-02-23
    • 2015-11-24
    • 2020-10-08
    • 2012-09-21
    • 2014-06-08
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多