You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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:

  1. 在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>
  1. 在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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.21 15:03:25