Android中OS /用户在游戏崩溃/杀死游戏时文件操作失败


13

我的游戏在固定间隔后将其状态保存在游戏/应用内部存储器中的文件上。当我的游戏分别被用户或操作系统杀死或崩溃时,我们在该文件上写入当前游戏状态。修复间隔后的文件写入工作正常,但是当游戏因OS或用户崩溃/被杀死时,文件写入操作将失败。操作失败会导致游戏状态不完整或游戏状态为空,即完全没有数据写入文件。我已经尝试过使用android服务的多种解决方案,以防该服务为NON STICKY服务被该应用杀死。另一方面,如果服务为STICKY,则它将重新启动,但最初随服务附加的意图为空或新的。

问题是,当我的游戏/应用被用户/操作系统杀死后,如何将我的数据(大约〜2-3MB)完全保存在内部存储中的文件中?


您必须处理SIGTERM和SIGKILL(也许不是SIGKILL,Android可能正在使用SIGTERM)。(没有时间研究/写下完整的答案,但这是基本想法。)
约翰·汉密尔顿

2
根据定义,@ JohnHamilton SIGKILL无法处理。
Darkhogg

@Darkhogg好吧,那不是在Unity中。(我确实为此目的而在某个时刻更改了一个项目的linux内核,当然也可以让程序处理SIGKILL)
John Hamilton

Answers:


20

我建议以双缓冲方式写入保存状态,这在过去的控制台标题中很常见(在这种情况下,您必须应付在写入过程中取出存储卡,并且写入速度很慢)。

保存:

  • 如果不存在文件,则将状态写入文件A
  • 如果存在A,写给B
  • 如果A和B都存在,则找出哪个较旧,将其删除,然后写入该一个

加载:

  • 如果A和B都存在,请尝试加载两者中的较新版本。如果失败(因为文件不完整或损坏),请将其删除并加载另一个
  • 如果只有一个,则加载它
  • 如果两者都损坏,则通知用户其保存状态不可恢复(就像您可能已经必须那样)

即使应用在写入过程中被杀死,此流程也将确保您的存储中始终至少存在一个有效的保存。自从上次保存以来,如果发生此类失败,玩家将不会获得游戏状态的任何更改,但不必重新开始。

此外,除了保存间隔外,您还应该在关键事件(例如,应用内购买)之后立即进行保存,以最大程度地减少崩溃/死亡会导致该关键事件丢失的脆弱性窗口。这也可以防止游戏漏洞(例如,在失去生命后强制杀死应用程序,因为您知道自己会从失去生命之前恢复到游戏状态,然后重试)。当然,如果要这样做,则必须使用表示“如果正在进行保存,请勿尝试再次开始保存”的逻辑来保护间隔保存。


谢谢MrCranky,这是我的问题的部分解决方案,我该如何保存上次会话的数据,即在杀死应用程序/游戏之前?例如,他进行了应用内购买并杀死了应用。
法萨尔·伊姆兰

12
您甚至不需要两个文件。如果仅在成功写入后写入B,则删除A并将B重命名为A。java.nio.file.Files.move(Path source, Path target, CopyOption... options)可以将重命名和覆盖作为原子操作进行。
Polygnome

6
@Polygnome:请注意,在断电的情况下,这将无法始终提供您所期望的保证,除非您sync()在将文件B移到文件A之前调用文件B(即使这样也没有完整的保证,但sync()还算不错)。
Dietrich Epp '18

1
@FaisalImran在重要操作之后(例如在IAP之后)立即保存数据。如果操作因电话关闭而中断,我想它永远也不会从这个人那里拿钱。但以防万一,您可能希望在某个平台上的购买中保存他的帐户数据,以尝试购买某种东西。然后,您可以将您的收入与该数据进行比较,看看这个人是否真的买了东西。然后通过您用来保存所有数据的在线服务为他打开此功能。如果您将本地保存用于IAP,那么比这个问题还要糟糕。
坦率的月亮_Max_

1
最后,尽管这可能无法解决您的所有问题,但是我想说您的问题还不能完全解决。您不能同时支持“用户可能随时杀死我的应用程序”和“绝不丢失任何数据”,因为在事件发生之后但在将其持久存储到用户之前,总会有一个窗口可能会杀死该应用并丢失数据。
MrCranky

3

Android仅在后台运行时杀死应用程序。当应用程序在后台运行时,您的游戏数据确实需要更新吗?还是可以停止更新数据,直到应用程序返回到前台为止?如果您可以获取事件历史记录或当应用程序返回到前台时仅获取当前状态,则即使在多人游戏中,您也可以推迟更新。为了CPU,网络和电池效率的提高,您可能应该考虑这样做。

如果用户终止了您的应用,则正在运行的服务应会收到的呼叫onTaskRemoved。我不知道如果您尝试用这种方法做很多处理会怎样。我希望如果它在一定时间内没有返回,Android将为kill -9您提供应用程序。


应用程序不需要在后台进行更新,但是应用程序必须先保存其数据(即json文件),然后才能进入后台或销毁应用程序。
Faisal Imran

你是对的onTaskRemoved方法将调用,但是保存文件所需的时间更多,或者我们可以说计算时间很大。当用户杀死该应用程序时,此方法将停止。
Faisal Imran
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.