【问题标题】:Files not being written to device文件未写入设备
【发布时间】:2012-06-26 01:57:55
【问题描述】:

我已经尝试了一百种不同的方法来解决我的问题,但由于某种原因,它们根本行不通。 我正在尝试一种快速而肮脏的方式,以使我的应用程序持久化。它基本上得到了很多在销毁时需要保存的对象,所以我想我会让它把对象放入一个 ArrayList 中,然后使用 ObjectOutputStream 将 ArrayList 写入文件。

public void onStop() {
    super.onStop();
    Log.d("Event", "Stopped");
    FileOutputStream fos = null;
    ObjectOutputStream oos = null;
    try {
        fos = openFileOutput("Flights", MODE_WORLD_WRITEABLE);
        oos = new ObjectOutputStream(fos);
    } catch (FileNotFoundException e) {
        e.printStackTrace();
    } catch (IOException e) {
        e.printStackTrace();
    }
    ArrayList<Flight> alFlightList = new ArrayList<Flight>();
    Iterator it = flightMap.entrySet().iterator();
    while (it.hasNext()) {
        Map.Entry pairs = (Map.Entry)it.next();
        alFlightList.add((Flight) pairs.getValue());
    }
    try {
        oos.writeObject(alFlightList);
        oos.close();
    } catch (IOException e) {
        e.printStackTrace();
    } finally {
        Log.d("Info", "File created!");
    }      
}

我得到了一个类似的算法来再次读取它,但它抱怨没有任何文件可供读取。 我知道使用文件进行持久性不是最佳实践,但正如前面提到的,这应该是一个快速而肮脏的解决方案。 (但我现在用在上面的时间,还不如花在制作数据库上。._。) 谢谢!

【问题讨论】:

  • onDestroy() 不能保证被调用。尝试进行一些登录以查看实际情况。更像是您希望将保存移动到 onPause() 或 onStop() 因为这些是应用程序变得可终止的点(取决于 android 版本 - 请参阅活动生命周期文档)。也有可能在您的测试中 onDestroy() 根本没有发生,因为没有必要销毁活动。当然,你的阅读算法应该处理没有什么可以恢复的情况,因为它可能是第一次运行。
  • 我想过这个问题,并且一直在记录所有发生的事件,但即使它确实摧毁了很多次,它仍然没有工作。 (虽然移动它的想法是个好主意,一旦这个问题得到解决,我就会这样做。)
  • 通过上面的代码添加额外的日志记录,这样你就知道它有多远了。您确定日志中已经没有错误了吗?另外,在 adb shell 中使用 run-as your.package.name 并手动检查文件是否存在。
  • 您绝对不想在onDestroy... 中执行 I/O,浏览此帖子的人会立即意识到这是问题所在。如果您已将此代码移出 onDestroy,那么我建议您使用当前代码更新您的帖子。
  • 正式注明,并更改。

标签: java android file fileoutputstream objectoutputstream


【解决方案1】:

来自Saving Persistent State 上的文档,

除了一个activity,一般有两种持久化状态 将处理:共享的类似文档的数据(通常存储在一个 使用内容提供程序的 SQLite 数据库)和内部状态,例如 用户偏好。

对于内容提供者数据,我们建议活动使用“edit in 放置”用户模型。也就是说,用户所做的任何编辑都是有效的 立即制作,无需额外的确认步骤。 支持这个模型一般是以下两个简单的事情 规则:

当创建一个新文档时,支持数据库条目或文件 它是立即创建的。例如,如果用户选择写一个 新电子邮件,该电子邮件的新条目会在他们 开始输入数据,这样如果他们在之后去任何其他活动 此时,这封电子邮件现在将出现在草稿列表中。当一个 Activity 的 onPause() 方法被调用,它应该提交到后台 内容提供者或文件用户所做的任何更改。这确保 这些变化将被即将发生的任何其他活动看到 跑步。您可能希望更积极地提交数据 在活动生命周期的关键时刻:例如之前 开始一项新的活动,在完成自己的活动之前,当 用户在输入字段之间切换等。

因此,如果您想“正确”执行此操作,我会将数据保存在 onPause... 中,并且我可能会使用某种 SQLite 数据库保存状态。您还应该使用 AsyncTask 在单独的线程上执行文件 I/O,因为这种事情可能会阻塞 UI 线程并导致您的应用程序崩溃。

如果您想要一种快速而肮脏的方式来做到这一点(即如果您没有在 Android 市场上发布此应用程序),那么我敢打赌,问题在于您正在尝试执行onDestroy 中的文件 I/O,不保证会被调用。这是在onPause 中执行文件读/写的另一个原因。

我建议的最后一件事是阅读internal/external storage 上的文档。可能是您没有写入正确的目录,因为您没有这样做的文件权限。您应该像这样执行文件 I/O:

String FILENAME = "FLIGHTS";

FileOutputStream fos = openFileOutput(FILENAME, Context.MODE_PRIVATE);
fos.write(...);
fos.close();

【讨论】:

  • 感谢您的回复,但正如我还向 Chris Stratton 提到的那样,我正在记录所有事件,并确保 onDestroy 实际运行。另一方面,我已将其移至 onPause 并获得相同的结果。但是,是的,我知道这是非常糟糕的道德规范,但现在我刚刚对这个问题感到恼火,并且想知道我做错了什么,因为我将来可能需要使用文件。
  • 查看我的帖子...这就是您应该如何对内部存储执行文件读/写操作。也请查看我帖子中的文档。对 SD 卡的外部写入遵循类似的做法。
  • 您能否发布一个使用该代码编写对象的示例?因为我认为我正在这样做,使用 ObjectOutputStream,但这是错误的,或者?
  • 或许您需要将alFlightlist转换为字节数组,然后写入文件?
  • 我现在正式放弃了。我在这方面花费的时间比我需要的要多,现在在使用字节数组时,我遇到了无数其他错误。不过感谢您的帮助。我现在只是在做一个血腥的数据库。 :) 接受这个作为答案,因为这是我得到的最接近的答案。
【解决方案2】:

替换 /sdcard/Flights 中的 Flight,否则它会在空空间中创建一个文件。 :) 我不确定它是否会起作用。

【讨论】:

  • 然后我得到一个错误:“文件 /sdcard/Flights 包含路径分隔符”
  • 其实openFileOutput()引用的是应用内部存储的私有区域。
  • 我的想法完全正确。仍然认为值得一试。
【解决方案3】:

为什么不使用数据库?并在创建或重新启动应用程序时从数据库中回调所有设置?

您也可以使用 onpause() 或 onstop() 方法将所有数据存储到数据库中。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-03-06
    • 1970-01-01
    • 1970-01-01
    • 2021-02-05
    • 2018-09-01
    • 2019-12-13
    相关资源
    最近更新 更多