Android迁移SQLite数据库后出现no such table:countries错误如何解决
问题根源分析
- 数据库路径拼接错误
原代码中数据库路径的拼接逻辑完全错误:myContext.filesDir.path + myContext.packageName + "/databases/"得到的路径为/data/data/[你的包名]/files[你的包名]/databases/,该路径并非Android系统默认的数据库存储路径,导致你从assets复制的数据库存到了错误位置,SQLiteOpenHelper打开的是默认路径下的空数据库,自然找不到表。
你提到的/data/user/0/[包名]/是Android 6.0及以上系统多用户模式下的正常软链接,会自动指向当前用户对应的/data/data/[包名]/目录,不是错误原因。 - SQLiteOpenHelper逻辑错误
onCreate方法为空,没有建表逻辑(你使用预制数据库的场景下这个本身没问题,但后续调用逻辑存在错误)onOpen中强制调用onCreate属于无效操作,空实现的onCreate不会生成任何表- 先调用
dbHelper.readableDatabase会先在默认路径生成一个空的同名数据库,后续即使你复制了正确的数据库也可能被覆盖或者无法生效
- 后续修复逻辑错误
你修改后的打开数据库代码中,传入openDatabase的dbPath是目录路径,不是Location.db的完整路径,自然也找不到数据库文件。
修复方案
第一步:修正数据库路径获取逻辑
不要手动拼接路径,直接使用Android系统提供的API获取正确路径,兼容所有系统版本:
// 初始化块修改为以下内容 init { // 直接获取系统默认的数据库文件完整路径 val dbFile = myContext.getDatabasePath(DB_NAME) // 取数据库所在的目录路径 dbPath = dbFile.parentFile?.absolutePath + "/" dbHelper = DatabaseHelper(myContext) }
第二步:修正预制数据库复制逻辑
复制前先判断databases目录是否存在,不存在则先创建,同时调整createDataBase的逻辑,避免提前触发空库创建:
@Throws(IOException::class) fun createDataBase() { val dbExist = checkDataBase() if (!dbExist) { // 先创建databases目录,避免复制失败 val dbDir = File(dbPath) if (!dbDir.exists()) { dbDir.mkdirs() } try { copyDataBase() } catch (e: IOException) { throw Error("Error copying database") } } }
第三步:清理SQLiteOpenHelper的无效逻辑
删掉onOpen中的无用代码,onUpgrade如果没有迁移逻辑可以暂时保留空实现或者补充你需要的逻辑:
inner class DatabaseHelper(context: Context?) : SQLiteOpenHelper(context, DB_NAME, null, 5) { override fun onCreate(db: SQLiteDatabase) {} override fun onUpgrade(db: SQLiteDatabase, oldVersion: Int, newVersion: Int) { // 版本升级时如果需要覆盖数据库可以保留复制逻辑,否则按需修改 if(newVersion>oldVersion) { copyDataBase() } } }
第四步:修正数据库调用逻辑
数据库操作前必须先调用createDataBase()确保预制库复制完成,再调用openDB()打开数据库,不要在getter里重复打开数据库。
验证方法
修改完成后完全卸载应用重新安装,通过Device File Explorer检查/data/data/[你的包名]/databases/下的Location.db大小是否和assets下的预制库大小一致,如果一致说明复制成功,此时再执行查询操作即可正常找到表。
内容的提问来源于stack exchange,提问作者mr. groot
相关产品推荐
相关产品推荐

