好的,我在桌面上使用了SQLite3创建了一个仅需读取的某些信息的数据库。我正在制作的应用程序不需要向此表中插入或删除信息。
我已经在Google上搜索了Room数据库层的大量文档,其中所有文档都涉及在构建应用程序时在Room中创建一个全新的数据库 - 这不是我想要的,因为我已经有了一个。
我该如何让Room读取已经存在的数据库?我的数据库目前存储在/app/src/main/assets/splitbilldatabase.db
中。
好的,我在桌面上使用了SQLite3创建了一个仅需读取的某些信息的数据库。我正在制作的应用程序不需要向此表中插入或删除信息。
我已经在Google上搜索了Room数据库层的大量文档,其中所有文档都涉及在构建应用程序时在Room中创建一个全新的数据库 - 这不是我想要的,因为我已经有了一个。
我该如何让Room读取已经存在的数据库?我的数据库目前存储在/app/src/main/assets/splitbilldatabase.db
中。
Room.databaseBuilder(appContext, AppDatabase.class, "splitbilldatabase.db")
.createFromAsset("splitbilldatabase.db")
.build()
更多信息请参见:https://developer.android.com/training/data-storage/room/prepopulate
首先,您需要为Room模式创建所有要导入的内容(@Database、@Entity等表格),这些内容必须完全匹配要导入的数据库的模式。
外部数据库文件应该被复制(就像您所做的)到assets文件夹中。
然后,您可以在任何尝试打开Room数据库之前将文件复制,例如在RoomDatabase
的init
方法中,但是仅当文件/数据库不存在时才能这样做。
以下是一个可行的(但未经过广泛测试的)示例:
@Database(entities = {MyTable.class,
MyOthertable.class,
MyMappingTable.class},version = 1,
exportSchema = false)
public abstract class MyDatabase extends RoomDatabase {
public static final String DBNAME = "splitbilldatabase.db";
public static final String TB_MYTABLE = "mytable";
public static final String TB_MYOTHERTABLE = "myothertable";
public static final String TB_MYMAPPINGTABLE = "mymappingtable";
public static final String COL_MYTABLE_ID = BaseColumns._ID;
public static final String COL_MYTABLE_NAME = "_name";
public static final String COL_MYTABLE_DESCRIPTION = "_description";
public static final String COL_MYOTHERTABLE_ID = BaseColumns._ID;
public static final String COL_MYOTHERTABLE_OTHERDETAILS = "_otherdetails";
public static final String COL_MYMAPPINGTABLE_MYTABLEREFERENCE = "_mytable_reference";
public static final String COL_MYMAPPINGTABLE_MYOTEHERTABLEREFERENCE = "_myothertable_reference";
public abstract MyTableDao myTableDao();
public abstract MyOtherTableDao myOtherTableDao();
public abstract MyMappingTableDao myMappingTableDao();
public MyDatabase() {
super();
}
@Override
public void init(@NonNull DatabaseConfiguration configuration) {
importExistingDatabase(configuration.context, true); //<<<<<<<<<< Invokes the Import of the Exisiting Database.
super.init(configuration);
}
private void importExistingDatabase(Context context, boolean throw_exception) {
int buffer_size = 32768;
File dbpath = context.getDatabasePath(DBNAME);
if (dbpath.exists()) {
return; // Database already exists
}
// Just in case make the directories
File dirs = new File(dbpath.getParent());
dirs.mkdirs();
int stage = 0;
byte[] buffer = new byte[buffer_size];
long total_bytes_read = 0;
long total_bytes_written = 0;
int bytes_read = 0;
try {
InputStream assetdb = context.getAssets().open(DBNAME);
stage++;
dbpath.createNewFile();
stage++;
OutputStream realdb = new FileOutputStream(dbpath);
stage++;
while((bytes_read = assetdb.read(buffer)) > 0) {
total_bytes_read = total_bytes_read + bytes_read;
realdb.write(buffer,0,bytes_read);
total_bytes_written = total_bytes_written + bytes_read;
}
stage++;
realdb.flush();
stage++;
assetdb.close();
stage++;
realdb.close();
stage++;
} catch (IOException e) {
String failed_at = "";
switch (stage) {
case 0:
failed_at = "Opening Asset " + DBNAME;
break;
case 1:
failed_at = "Creating Output Database " + dbpath.getAbsolutePath();
break;
case 2:
failed_at = "Genreating Database OutputStream " + dbpath.getAbsolutePath();
break;
case 3:
failed_at = "Copying Data from Asset Database to Output Database. " +
" Bytes read=" + String.valueOf(total_bytes_read) +
" Bytes written=" + String.valueOf(total_bytes_written);
break;
case 4:
failed_at = "Flushing Written Data (" +
String.valueOf(total_bytes_written) +
" bytes written)";
break;
case 5:
failed_at = "Closing Asset Database File.";
break;
case 6:
failed_at = "Closing Created Database File.";
}
String msg = "An error was encountered copying the Database " +
"from the asset file to New Database. " +
"The error was encountered whilst :-\n\t" + failed_at;
Log.e("IMPORTDATABASE",msg);
e.printStackTrace();
if (throw_exception) {
throw new RuntimeException(msg);
}
}
}
}