如何使用带有预填充数据库的 Room Persistence Library?

How to use Room Persistence Library with pre-populated database?

我想将 Room 与预填充的数据库一起使用,但我不明白如何告诉 Room 在哪里可以找到我的数据库。

我现在把它放在 src/main/assets/databases 中,当我为 Room 数据库创建实例时,我是这样创建的:

Room.databaseBuilder(
    getApplicationContext(),
    AppDatabase.class,
    "justintrain.db"
)
.allowMainThreadQueries()
.build();

不过,我认为它每次都在创建一个新数据库,或者无论如何,它没有使用预先填充的数据库。

我怎样才能找到我的数据库?

这就是我解决它的方法,以及如何使用预填充的数据库(最高 Room v. alpha5)发布您的应用程序

  • 将您的 SQLite 数据库 database_name.db 放入 assets/databases 文件夹

  • 获取文件 from this repo 并将它们放入名为 sqlAsset

  • 的包中
  • 在您的 AppDatabase class 中,相应地修改您房间的数据库创建代码:

    Room.databaseBuilder(context.getApplicationContext(), 
                         AppDatabase.class, 
                         "database_name.db")
    .openHelperFactory(new AssetSQLiteOpenHelperFactory())
    .allowMainThreadQueries()
    .build();
    

请注意,您必须使用 "database_name.db" 而不是 getDatabasePath() 或其他方法:它只需要文件的名称。

你只需将 assets/databases 复制到 app/databases
然后在 databaseBuilder
中添加 addMigrations() 它会保留你的数据

我遇到了同样的问题,所以我创建了一个库来解决这个问题。 已接受的答案有效,但我认为使用库更容易。

AppDatabase db = RoomAsset
    .databaseBuilder(context.getApplicationContext(), AppDatabase.class, "database_name.db")
    .build(); 

将其添加到存储库末尾的根 build.gradle:

allprojects {
    repositories {
        ...
        maven { url "https://jitpack.io" }
    }
}

添加依赖

dependencies {
    // ... other dependencies
    implementation 'com.github.humazed:RoomAsset:v1.0'
}

你可以在这里找到图书馆:https://github.com/humazed/RoomAsset

更新(2019 年 11 月 7 日)

Room 现在支持使用开箱即用的预打包数据库,自版本 2.2.0

https://developer.android.com/jetpack/androidx/releases/room#2.2.0

2.2.0版本之前的解决方案:没有任何其他外部库的简单解决方案。

Room 依赖于现有的 Android 框架代码来创建或打开数据库。如果您查看 FrameworkSQLiteOpenHelperSQLiteOpenHelper 的 Room 版本)的源代码,它会在需要时在内部调用 SQLiteOpenHelper.getReadableDatabase() 和其他方法。

因此,最简单的解决方案是在使用 Room 创建数据库之前,将数据库文件从资产目录复制到 mContext.getDatabasePath("my-database.sqlite")

在你的例子中,代码看起来像这样 -

private final String DB_NAME = "my-database.sqlite";

private MyDatabase buildDatabase(Context context) {
    final File dbFile = context.getDatabasePath(DB_NAME);

    if(!dbFile.exists()) {
        copyDatabaseFile(dbFile.getAbsolutePath());
    }

    return Room.databaseBuilder(context.getApplicationContext(),
        MyDatabase.class, DB_NAME)
        .build();
}

private void copyDatabaseFile(String destinationPath) {
    // code to copy the file from assets/database directory to destinationPath
}

此 link 具有复制数据库所需的代码 - link with code

不使用外部库但有空间的类似解决方案: 1.将您的数据库复制到资产文件夹中 2. 从资产文件夹复制你的数据库

public class MainActivity extends AppCompatActivity {

public static AppDatabase db;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    copyDatabase(getApplicationContext(), "yourdatabase.db");

    db = Room.databaseBuilder(getApplicationContext(), .class, "yourdatabase.db").allowMainThreadQueries().build();
}

private void copyDatabase(Context context, String databaseName) {
    final File dbPath = context.getDatabasePath(databaseName);

    // If the database already exists, return
    if (dbPath.exists()) {
        Log.d("Activity", "db Path Exists");
        return;
    }

    // Make sure we have a path to the file
    dbPath.getParentFile().mkdirs();

    // Try to copy database file
    try {
        final InputStream inputStream = context.getAssets().open(databaseName);
        final OutputStream output = new FileOutputStream(dbPath);

        byte[] buffer = new byte[8192];
        int length;

        while ((length = inputStream.read(buffer, 0, 8192)) > 0) {
            output.write(buffer, 0, length);
        }

        output.flush();
        output.close();
        inputStream.close();
    }
    catch (IOException e) {
        Log.d("Activity", "Failed to open file", e);
        e.printStackTrace();
    }
}

}

2019 年的工作解决方案,没有黑客攻击或依赖项 (Kotlin)

  1. 将您的 .db 文件放在 assets/databases 中(或者任何文件夹,只要它在 assets 下)。

  2. 使用Room 2.2现有的createFromAsset()函数,传入数据库路径。例如,如果您的数据库文件名为 my_data.db 并且位于 assets 文件夹的 databases 目录下,那么您将执行 createFromAsset("databases/my_data.db").

假设您的数据库名称(例如,my_data)存储在名为DATABASE_NAME的常量变量中,您可以使用此示例代码:

Room.databaseBuilder(
                    context.applicationContext,
                    MyDatabase::class.java,
                    DATABASE_NAME
                )
                    .createFromAsset("databases/$DATABASE_NAME.db")
                    .build()

重要提示:确保数据class/entity 的架构与.db 文件的架构完全匹配。例如,如果一个列在 .db 文件中没有明确标记为 NOT NULL,那么这意味着该列可以有 null 其中的价值观。在 Kotlin 中,您必须将其与数据 class 中的 val colName: dataType? = null 相匹配。如果您只执行 val colName: dataType,Kotlin 会将其编译为 NOT NULL 列,并且当您尝试 运行 您的应用程序时会抛出异常。

注意:如果您想从下载到 Android 设备本身的数据库文件创建 Room 数据库,您也可以使用 createFromFile() 函数。查看 official documentation 如何执行此操作。

从 Room 2.2 开始,您可以使用以下命令预填充数据库:

Room.databaseBuilder(appContext, TestDatabase.class, “Sample.db”)
    .createFromAsset(“database/myapp.db”)
    .build()

Room 现在支持预填充数据库。只需使用 SQLite Browser 之类的程序或您选择的任何其他程序来准备您的数据库。然后把它放在 Assets Folder 中,可能在一个名为 database 的子文件夹中,然后调用:

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

如果您没有将数据库作为资产提供,但您下载了它或者它在文件系统中,那么方法是:

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

有关此功能的更多描述或数据库迁移,您可以查看 Documentation Training