【问题标题】:How to handle forced android application termination while writing a file?如何在写入文件时处理强制 android 应用程序终止?
【发布时间】:2026-01-06 07:40:02
【问题描述】:

对于 Android 的游戏应用程序,我通过将玩家信息写入文件来保存它。然而,在实际文件写入期间,应用程序可能会被强制终止,结果是用户下次玩游戏时所有信息都丢失了,因为正在写入的保存文件是空的。有没有办法解决?这是我将文件写入存储的方式:

        String data = "SAVEDATA";
        try {
            FileOutputStream outputStream;
            File file = new File("file.txt");
            outputStream = new FileOutputStream(file, false);
            outputStream.write(data.getBytes());
            outputStream.close();
        } catch (Exception e) {
            e.printStackTrace();
        }

如果用户在写入文件时结束进程,则不会向文件写入任何内容,并且之前的所有保存数据都会丢失(因为每次保存都会覆盖文件)。避免这种情况的最佳方法是什么?

编辑:我不是在寻找另一种方法来保存我的数据,我绝对希望将其作为保存在手机存储中的文件。我只想知道当用户在写入保存文件时结束应用程序进程时如何防止数据丢失。

EDIT2:在需要保存游戏数据时启动服务是否是个好主意,这样即使应用程序被终止,服务仍在保存数据时仍在运行,然后服务可以自行结束保存后呢?

【问题讨论】:

  • 我在 onPause 上执行此操作,除非用户在执行 onPause 函数时结束应用程序进程,否则它工作得非常好。如果用户结束该过程,则保存文件不会被写入,但已被清除,因此保存数据丢失。

标签: android file-io


【解决方案1】:

您可以使用 Android 的 AtomicFile,它可以通过创建备份文件来确保以原子方式写入文件。 https://developer.android.com/reference/android/support/v4/util/AtomicFile.html

示例:

    String data = "SAVEDATA";
    File file = new File("file.txt");
    AtomicFile atomicFile = new AtomicFile(file);
    FileOutputStream fos = null;
    try {
           fos = atomicFile.startWrite();
           fos.write(data.getBytes());
           atomicFile.finishWrite(fos);
    }catch(IOException e){
           atomicFile.failWrite(fos);
           throw e;
    }

【讨论】:

    【解决方案2】:

    如果您要保存字符串或原始值,则应改为使用共享首选项,这是一个解释其用法的链接: http://developer.android.com/guide/topics/data/data-storage.html#pref

    【讨论】:

    • 我正在保存一个字符串,但我希望它是一个实际的文件,以便在设备之间更轻松地传输数据。
    【解决方案3】:

    首先,避免覆盖您的旧存档。将您的保存命名为:save_1save_2save_3、... save_n不再需要。

    另一个好主意是在用户完成游戏后立即自动保存。这可以最大限度地减少用户的进度在易失性内存中保存的时间。

    如果您的游戏代码在 Activity 中运行,您也可以保存在 onPause 方法中。

    如果您的游戏代码在后台服务中运行,并且用户从 Android 的设置菜单(或使用进程杀手)手动结束您的进程,那么您的服务的 onDestroy 方法将被调用,因此您可以保存在该方法中。

    编辑:如果您遇到的问题是您的用户从“应用程序无响应”对话框中关闭了您的应用程序,则根本原因可能是您正在 UI 线程上保存。尝试启动 AsyncTask 或 IntentService 来进行保存。

    【讨论】:

    • 我已经考虑了您的第一点,这似乎是我目前最好的选择,实施起来并不难。这似乎不是一个好的解决方案。最大的问题不是保存在易失性存储器中的数据丢失了;就是整个保存文件被完全擦除并消失了,因此之前游戏会话的所有数据也消失了。
    • 我正在使用 onPause 方法来保存数据,但是如果该过程结束,onPause 方法不会一直执行。我不确定后台服务的工作方式是否与活动不同,但是当我尝试结束我的应用程序的进程(它是活动而不是服务)时,没有调用 onDestroy 函数。当进程被杀死时,onPause 函数也不会被调用(当然,除非进程在被杀死之前已经暂停)。
    • 是的,如果保存需要很长时间,您不应该在 UI 线程上执行此操作。请参阅 AsyncTask 和 IntentService 了解在单独线程上执行任务的两种不同方式。
    • 一个 IntentService 和 AsyncTask 都会在实际进程被杀死的同时被杀死,所以并不能解决问题。
    • 很多人喜欢杀死他们设备上所有正在运行的应用程序,尤其是在一些让他们很容易杀死正在运行的应用程序的设备上,例如:youtube.com/watch?v=Vqv_q5rGAfQ我自己有一个习惯这样做很多并关闭我手机上正在运行的应用程序,但不幸的是这会破坏保存过程。如果我启动一项服务并且用户像上面的视频中那样做,那么该服务也会停止吗?还是只有设置中的“强制停止”按钮才停止服务?
    【解决方案4】:

    将您的数据保存在onPause 是可行的方法;进一步阅读下面data storage

    1. Shared Preferences
    2. Files
    3. Databases
    4. Content Providers

    进一步阅读here基本数据存储

    希望对你有帮助:)

    【讨论】:

    • 我目前正在使用 onPause 函数来保存我的数据。但是,如果用户在 onPause 函数运行时结束进程,则它会在中间停止执行并导致保存文件损坏,因为它正在覆盖的文件已被清除,但尚未添加新数据。我可以在我的 Galaxy S3 手机上轻松重现这一点,因为我正在保存一个相当大的保存文件,需要相当长的时间才能完全写入。
    • 好的,我想绕过的方法是创建一个服务。在将被杀死的不同进程上启动它onPause,在保存数据后使用stopSelf 杀死它。
    最近更新 更多