Android(Kotlin)中如何实现Room数据库的导入导出与分享功能?
Room数据库导入导出+分享实现方案(新手友好)
一、核心原理
Room本质是SQLite数据库,导入导出的核心就是复制SQLite数据库文件:
- 导出:把App私有目录下的Room数据库文件复制到外部可访问目录,再通过系统分享功能发送
- 导入:接收外部的数据库文件,替换App私有目录下的原数据库文件
二、前置准备
1. 权限配置
在AndroidManifest.xml中添加权限:
<!-- Android 9及以下读写外部存储权限 --> <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" /> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> <!-- Android 10+ 可选,用于访问公共目录 --> <uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE" />
注意:代码中必须动态申请这些权限,否则会触发权限异常。
2. FileProvider配置(Android 7+ 必加)
Android 7以上禁止直接暴露File Uri,需用FileProvider生成安全Uri:
- 在
res/xml目录下创建file_paths.xml:
<?xml version="1.0" encoding="utf-8"?> <paths xmlns:android="http://schemas.android.com/apk/res/android"> <!-- 共享下载目录文件 --> <external-path name="external_files" path="Download/" /> <!-- 共享App私有数据库目录文件 --> <files-path name="internal_db" path="databases/" /> </paths>
- 在
AndroidManifest.xml的<application>标签内注册FileProvider:
<provider android:name="androidx.core.content.FileProvider" android:authorities="${applicationId}.fileprovider" android:exported="false" android:grantUriPermissions="true"> <meta-data android:name="android.support.FILE_PROVIDER_PATHS" android:resource="@xml/file_paths" /> </provider>
三、导出功能实现
步骤1:获取Room数据库源文件路径
Room数据库默认存在/data/data/你的包名/databases/目录,文件名是创建RoomDatabase时指定的名称(比如MyDatabase.db)。
通过RoomDatabase实例获取路径:
// 假设你的RoomDatabase实例为myDatabase val dbFile = myDatabase.openHelper.writableDatabase.path val sourceFile = File(dbFile)
步骤2:复制数据库到外部目录
将文件复制到Download目录,方便用户找到并分享:
fun exportDatabase(context: Context, dbName: String) { val sourceFile = File(context.getDatabasePath(dbName).absolutePath) val targetDir = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS) val targetFile = File(targetDir, "${dbName}_${System.currentTimeMillis()}.db") try { Files.copy(sourceFile.toPath(), targetFile.toPath(), StandardCopyOption.REPLACE_EXISTING) shareDatabaseFile(context, targetFile) } catch (e: IOException) { e.printStackTrace() Toast.makeText(context, "导出失败:${e.message}", Toast.LENGTH_SHORT).show() } }
四、分享导出的数据库文件
用系统Intent实现多应用分享(支持WhatsApp、邮件等):
fun shareDatabaseFile(context: Context, file: File) { val uri = FileProvider.getUriForFile( context, "${context.packageName}.fileprovider", file ) val shareIntent = Intent(Intent.ACTION_SEND).apply { type = "application/sqlite" putExtra(Intent.EXTRA_STREAM, uri) addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION) } context.startActivity(Intent.createChooser(shareIntent, "分享数据库")) }
五、导入功能实现
步骤1:接收外部分享的文件
用Activity Result API获取分享的Uri(替代旧的onActivityResult):
private val importLauncher = registerForActivityResult(ActivityResultContracts.GetContent()) { uri: Uri? -> uri?.let { importDatabase(context, it) } } // 触发导入文件选择 fun startImport(context: Context) { importLauncher.launch("application/sqlite") }
步骤2:替换App私有数据库文件
导入前必须关闭当前Room数据库连接,避免文件被占用:
fun importDatabase(context: Context, sourceUri: Uri) { val dbName = "MyDatabase.db" // 你的Room数据库名称 val targetFile = File(context.getDatabasePath(dbName).absolutePath) // 关闭数据库连接(假设数据库实例在Application中维护) (context.applicationContext as MyApplication).closeDatabase() try { context.contentResolver.openInputStream(sourceUri)?.use { inputStream -> FileOutputStream(targetFile).use { outputStream -> inputStream.copyTo(outputStream) } } Toast.makeText(context, "导入成功,请重启应用", Toast.LENGTH_SHORT).show() } catch (e: IOException) { e.printStackTrace() Toast.makeText(context, "导入失败:${e.message}", Toast.LENGTH_SHORT).show() } finally { // 重新初始化数据库 (context.applicationContext as MyApplication).initDatabase() } }
补充:Application中管理数据库实例
为方便关闭和重启数据库,建议在Application类中维护单例:
class MyApplication : Application() { private var myDatabase: MyDatabase? = null override fun onCreate() { super.onCreate() initDatabase() } fun initDatabase() { myDatabase = Room.databaseBuilder( this, MyDatabase::class.java, "MyDatabase.db" ).build() } fun getDatabase(): MyDatabase = myDatabase!! fun closeDatabase() { myDatabase?.close() myDatabase = null } }
六、关键注意事项
- 动态权限申请:调用导出/导入前必须检查并申请读写权限,否则会抛出SecurityException
- Android 10+ 适配:目标版本为Android 10以上时,建议用MediaStore或SAF(存储访问框架)操作文件,避免
MANAGE_EXTERNAL_STORAGE权限的手动开启要求 - 数据一致性:导出时暂停数据库写入操作,避免文件不完整;导入前确保App未使用数据库,防止数据损坏
- 版本兼容:导入的数据库文件版本必须与当前App的Room数据库版本一致,否则会触发迁移失败
内容的提问来源于stack exchange,提问作者kunal sahu
相关产品推荐
相关产品推荐

