房间试图重新打开一个已经关闭的数据库

Room attempt to re-open an already closed database

在 Android 架构组件中使用 Room 时,我在尝试使用 Dagger 组件访问数据库时收到以下错误:

java.lang.IllegalStateException: attempt to re-open an already-closed object: SQLiteDatabase: (database path)

我使用的是 Dagger 版本 2.11 和 Room 版本 1.0.0-alpha7。该错误可在版本 1.0.0-alpha5.

上重现

在初始化数据库并将其注入我的 class 后,任何通过 DAO 访问数据库的尝试都会发生此错误。

这个问题的一个解决方案是删除数据库文件并重新开始。这不是问题,因为我只是在测试,可以使用在线数据重新填充数据库。

要这样做:

  • 应用信息 > 存储 > 清除数据
  • 手动删除位于 /data/data/com.app.example/databases/database.db
  • 的文件

这是因为您试图在不提供任何迁移信息的情况下修改现有数据库的架构。所以基本上它会尝试将新的数据库模式写入现有的数据库,但这是行不通的。

有两种解决方法。如果您在开发环境中,您可以回退到破坏性迁移,为此您的数据库创建代码将类似于以下内容:

MyDatabase myDatabase = Room.databaseBuilder(context, MyDatabase.class, "my-db")
    .fallbackToDestructiveMigration()
    .build();

这意味着当您为数据库提供更新的或新的实体时,它会执行@huw 的回答并仅删除应用程序安装中的数据库,从中删除所有数据并为您提供全新安装。

另一种方法是使用迁移功能。它们很长,所以除非有人要我把它写在这里,否则我会暂时保留它,但基本上,可以在这里找到文档:

Room DB Migration Documentation

这本质上是让DB运行一些自己提供的SQL更新数据库到新版本。通过这种方式,您可以确保 none 的数据在迁移时丢失;或尽可能少,具体取决于您在做什么。这是生产应用程序的首选方法,因为这意味着用户不会丢失他们预先存在的数据,并且您不会惹恼很多 reviews/lost 客户。

希望有所帮助!

我在迁移不太成功后遇到了这种异常。始终 double-check 您用于迁移的 SQL 查询。您可以使用错误类型的数据创建一个新列,并且异常的描述不会有帮助。