预填充 Room 数据库

有时,您可能希望您的应用在启动时就加载了特定数据。这被称为 _预填充_ 数据库。在 Room 2.2.0 及更高版本中,您可以使用 API 方法在初始化时预填充 Room 数据库,其中内容来自设备文件系统中的预打包数据库文件。

从应用资源预填充

要从位于应用 assets/ 目录中的任何位置的预打包数据库文件预填充 Room 数据库,请在调用 build() 之前,从您的 RoomDatabase.Builder 对象调用 createFromAsset() 方法。

Kotlin

Room.databaseBuilder(appContext, AppDatabase::class.java, "Sample.db")
    .createFromAsset("database/myapp.db")
    .build()

Java

Room.databaseBuilder(appContext, AppDatabase.class, "Sample.db")
    .createFromAsset("database/myapp.db")
    .build();

createFromAsset() 方法接受一个字符串参数,其中包含从 assets/ 目录到预打包数据库文件的相对路径。

从文件系统预填充

要从位于设备文件系统中的任何位置的预打包数据库文件预填充 Room 数据库(_除_ 应用的 assets/ 目录之外),请在调用 build() 之前,从您的 RoomDatabase.Builder 对象调用 createFromFile() 方法。

Kotlin

Room.databaseBuilder(appContext, AppDatabase::class.java, "Sample.db")
    .createFromFile(File("mypath"))
    .build()

Java

Room.databaseBuilder(appContext, AppDatabase.class, "Sample.db")
    .createFromFile(new File("mypath"))
    .build();

The createFromFile() method accepts a File argument for the prepackaged database file. Room 创建指定文件的副本,而不是直接打开它,因此请确保您的应用程序对该文件具有读取权限。

处理包含预先打包数据库的迁移

预先打包的数据库文件还可以改变 Room 数据库处理回退迁移的方式。通常,当 破坏性迁移 启用且 Room 必须执行没有迁移路径的迁移时,Room 会删除数据库中的所有表并创建一个具有指定架构的空数据库,以用于目标版本。但是,如果您包含一个与目标版本号相同的预先打包的数据库文件,Room 会尝试在执行破坏性迁移后使用预先打包的数据库文件的内容填充新创建的数据库。

有关 Room 数据库迁移的更多信息,请参阅 迁移 Room 数据库

以下部分介绍了几个实际示例。

示例:使用预先打包的数据库的回退迁移

假设以下情况

  • 您的应用程序定义了版本 3 的 Room 数据库。
  • 设备上已安装的数据库实例为版本 2。
  • 有一个版本为 3 的预先打包的数据库文件。
  • 没有从版本 2 到版本 3 的实现迁移路径。
  • 破坏性迁移已启用。

Kotlin

// Database class definition declaring version 3.
@Database(version = 3)
abstract class AppDatabase : RoomDatabase() {
    ...
}

// Destructive migrations are enabled and a prepackaged database
// is provided.
Room.databaseBuilder(appContext, AppDatabase::class.java, "Sample.db")
    .createFromAsset("database/myapp.db")
    .fallbackToDestructiveMigration()
    .build()

Java

// Database class definition declaring version 3.
@Database(version = 3)
public abstract class AppDatabase extends RoomDatabase {
    ...
}

// Destructive migrations are enabled and a prepackaged database
// is provided.
Room.databaseBuilder(appContext, AppDatabase.class, "Sample.db")
    .createFromAsset("database/myapp.db")
    .fallbackToDestructiveMigration()
    .build();

以下是这种情况下的情况

  1. 因为您应用程序中定义的数据库是版本 3,而设备上已安装的数据库实例是版本 2,所以需要进行迁移。
  2. 因为没有从版本 2 到版本 3 的实现迁移计划,所以迁移是回退迁移。
  3. 因为调用了 fallbackToDestructiveMigration() 构建器方法,所以回退迁移是破坏性的。Room 会删除设备上安装的数据库实例。
  4. 因为存在一个版本为 3 的预先打包的数据库文件,所以 Room 会重新创建数据库并使用预先打包的数据库文件的内容对其进行填充。另一方面,如果您的预先打包的数据库文件是版本 2,那么 Room 会注意到它与目标版本不匹配,并且不会将其用作回退迁移的一部分。

示例:使用预先打包的数据库的实现迁移

假设您的应用程序实现了从版本 2 到版本 3 的迁移路径

Kotlin

// Database class definition declaring version 3.
@Database(version = 3)
abstract class AppDatabase : RoomDatabase() {
    ...
}

// Migration path definition from version 2 to version 3.
val MIGRATION_2_3 = object : Migration(2, 3) {
    override fun migrate(database: SupportSQLiteDatabase) {
        ...
    }
}

// A prepackaged database is provided.
Room.databaseBuilder(appContext, AppDatabase::class.java, "Sample.db")
    .createFromAsset("database/myapp.db")
    .addMigrations(MIGRATION_2_3)
    .build()

Java

// Database class definition declaring version 3.
@Database(version = 3)
public abstract class AppDatabase extends RoomDatabase {
    ...
}

// Migration path definition from version 2 to version 3.
static final Migration MIGRATION_2_3 = new Migration(2, 3) {
    @Override
    public void migrate(SupportSQLiteDatabase database) {
        ...
    }
};

// A prepackaged database is provided.
Room.databaseBuilder(appContext, AppDatabase.class, "Sample.db")
    .createFromAsset("database/myapp.db")
    .addMigrations(MIGRATION_2_3)
    .build();

以下是这种情况下的情况

  1. 因为您应用程序中定义的数据库是版本 3,而设备上已安装的数据库是版本 2,所以需要进行迁移。
  2. 因为存在从版本 2 到版本 3 的实现迁移路径,所以 Room 会运行定义的 migrate() 方法将设备上的数据库实例更新到版本 3,保留数据库中已有的数据。Room 不会使用预先打包的数据库文件,因为 Room 仅在回退迁移的情况下使用预先打包的数据库文件。

示例:使用预先打包的数据库的多步骤迁移

预先打包的数据库文件还可以影响包含多个步骤的迁移。考虑以下情况

  • 您的应用程序定义了版本 4 的 Room 数据库。
  • 设备上已安装的数据库实例为版本 2。
  • 有一个版本为 3 的预先打包的数据库文件。
  • 存在从版本 3 到版本 4 的实现迁移路径,但没有从版本 2 到版本 3 的实现迁移路径。
  • 破坏性迁移已启用。

Kotlin

// Database class definition declaring version 4.
@Database(version = 4)
abstract class AppDatabase : RoomDatabase() {
    ...
}

// Migration path definition from version 3 to version 4.
val MIGRATION_3_4 = object : Migration(3, 4) {
    override fun migrate(database: SupportSQLiteDatabase) {
        ...
    }
}

// Destructive migrations are enabled and a prepackaged database is
// provided.
Room.databaseBuilder(appContext, AppDatabase::class.java, "Sample.db")
    .createFromAsset("database/myapp.db")
    .addMigrations(MIGRATION_3_4)
    .fallbackToDestructiveMigration()
    .build()

Java

// Database class definition declaring version 4.
@Database(version = 4)
public abstract class AppDatabase extends RoomDatabase {
    ...
}

// Migration path definition from version 3 to version 4.
static final Migration MIGRATION_3_4 = new Migration(3, 4) {
    @Override
    public void migrate(SupportSQLiteDatabase database) {
        ...
    }
};

// Destructive migrations are enabled and a prepackaged database is
// provided.
Room.databaseBuilder(appContext, AppDatabase.class, "Sample.db")
    .createFromAsset("database/myapp.db")
    .addMigrations(MIGRATION_3_4)
    .fallbackToDestructiveMigration()
    .build();

以下是这种情况下的情况

  1. 因为您应用程序中定义的数据库是版本 4,而设备上已安装的数据库实例是版本 2,所以需要进行迁移。
  2. 因为没有从版本 2 到版本 3 的实现迁移路径,所以迁移是回退迁移。
  3. 因为调用了 fallbackToDestructiveMigration() 构建器方法,所以回退迁移是破坏性的。Room 会删除设备上安装的数据库实例。
  4. 因为存在一个版本为 3 的预先打包的数据库文件,所以 Room 会重新创建数据库并使用预先打包的数据库文件的内容对其进行填充。
  5. 设备上安装的数据库现在是版本 3。因为这仍然低于您应用程序中定义的版本,所以需要进行另一个迁移。
  6. 因为存在从版本 3 到版本 4 的实现迁移路径,所以 Room 会运行定义的 migrate() 方法将设备上的数据库实例更新到版本 4,保留从版本 3 的预先打包的数据库文件中复制过来的数据。

其他资源

要了解有关预先填充 Room 数据库的更多信息,请参阅以下其他资源。

视频

博客