17

我想知道其他人在 Android 上保存文件时使用什么策略来避免数据丢失。我有几个游戏应用程序,本质上,它们可能会在用户暂停时保存游戏状态/保存游戏(onPause)。

这在 99.99% 的情况下都有效,但每隔一段时间我都会收到一个保存过程出错的保存游戏示例。通常,这是一个格式错误的 XML 文件,通常在某个任意点被截断。根据我收到的错误报告,我认为问题主要发生在用户在游戏过程中被电话或类似的东西打断,然后 Android 操作系统在应用程序完成保存之前将其杀死。保存文件的代码非常简单,所以我很难看出还有什么可能导致这个问题。

这是一个严重的问题,因为它通常会导致玩家的保存进度被破坏。

我想先写入一个空文件,然后再复制到“真实”文件,但我怀疑这只会增加问题,因为它总体上需要更多时间并且仍然有被中断的风险。

有谁有安全的方式来做到这一点,Android 相对保证不会搞砸?


如此总结,到目前为止建议的选项(据我了解):

  1. 为保存过程使用服务,假设这不太可能被操作系统杀死。
  2. 保存在临时文件中;验证保存后复制。
  3. 游戏状态的增量保存(我实际上已经将它用于玩家日志信息)。
  4. 2和3的组合。
  5. 将保存移到另一个线程,因为问题可能与 ANR 杀死 [DC 的评论如下]有关。

我认为 SharedPreferences 不适用于这种结构化数据,目前,这些方法似乎都不是理想的解决方案,所以我仍然愿意接受建议。


我还没有设法测试所有这些方法,因此我没有浪费赏金,而是将其分配给我认为最有可能解决问题的答案。不过,在接受答案之前,我仍计划检查各种选项。感谢所有好的建议。

4

5 回答 5

4

We've had occasional issues when we're doing I/O (usually writing) to persistent storage (private filesystem on internal memory) from the main thread. Usually this doesn't take much time at all, but occasionally it inexplicably takes ages (20 or 30 seconds or more). It seems that the Android filesystem implementations on some devices don't support concurrent access (see this, so your I/O can block if another process is using the filesystem. If you are doing your I/O on the main thread, the OS can/will kill your Activity if it blocks for too long. This may be what is happening to you.

Due to this problem, I would suggest that you move all your I/O to a separate thread (not the main thread). So, for example, to save the game state, in onPause() call a method that serializes the game state to a ByteArrayOutputStream which you then hand off to a separate thread to be written eventually to the filesystem.

于 2012-05-09T11:05:39.537 回答
4

这听起来像是一项服务的好工作。

http://developer.android.com/reference/android/app/Service.html

于 2012-04-20T19:03:37.420 回答
2

我认为在这种情况下,每次用户执行任何操作(不仅是在onPause()被调用时)都将一小部分数据(不是整个游戏状态)保存到数据库中是最好的方法。但是,这可能需要对代码进行大量修改。

折衷方案是将游戏状态拆分为更小的部分或子状态(例如 , round1, round2...,players等),并在用户执行任何操作时再次将数据存储到适当的文件中,而不是等待onPause()调用。这将显着降低丢失的概率,并且至少可以保证用户不会丢失整个游戏进度。此外,为避免在保存过程中断时可能出现的应用程序状态不一致,您最好先将数据保存到临时文件,并且只有在成功的情况下才简单地重命名文件,而不是复制其内容(比如说,round1.xml.tmp重命名到round1.xml)。

于 2012-05-05T08:17:34.150 回答
1

首先,我会尝试查看应用程序是否真的在没有通知的情况下被杀死,因为我认为情况不应该如此。应用程序可能会因为打电话之类的事情而停止,但我真的不认为 android 只是在没有任何通知的情况下杀死它。它可以决定结束它,但不能不保存状态等。

也许只是保存本身发生了错误。

一种不需要太多修改来检查的方法是使用校验和或使用其他方法来验证保存数据的完整性(大小、结束标记等)。您所要做的就是保存它,阅读并检查它(记录任何错误)并重复它直到它正确。如果你保存大量数据可能不是那么好,但对于纯粹的游戏数据来说应该没问题。

您还可以在应用程序启动和结束时设置一个状态,然后您会在下次启动时知道它上次是否正确结束以及是否需要采取额外措施。

于 2012-05-06T14:27:19.847 回答
0

如果可能的话SharedPreferences,用来存储你的游戏状态。只有在您调用后才会提交您的更改commit()。您可以在onSaveInstanceState回调中保存。在此处阅读文档。

于 2012-05-06T14:06:25.270 回答