如何使用带有预填充数据库的 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 框架代码来创建或打开数据库。如果您查看 FrameworkSQLiteOpenHelper
(SQLiteOpenHelper
的 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)
将您的 .db
文件放在 assets/databases
中(或者任何文件夹,只要它在 assets
下)。
使用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。
我想将 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 框架代码来创建或打开数据库。如果您查看 FrameworkSQLiteOpenHelper
(SQLiteOpenHelper
的 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)
将您的
.db
文件放在assets/databases
中(或者任何文件夹,只要它在assets
下)。使用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。