上一篇
安卓开发数据迁移
- 行业动态
- 2025-04-22
- 5
本地数据库迁移(SQLite/Room)
场景说明
当数据库结构发生变化(如新增表、修改字段类型)时,需确保新旧版本兼容。
实现方式
迁移类型 | 实现方式 |
---|---|
Room数据库 | 通过Migration 类定义版本升级逻辑,调用databaseBuilder 的addMigrations |
SQLite原生 | 重写SQLiteOpenHelper 的onUpgrade 方法,执行ALTER 语句 |
代码示例(Room)
// 定义迁移对象(从版本1升级到2) val MIGRATION_1_2 = object : Migration(1, 2) { override fun migrate(database: SupportSQLiteDatabase) { database.execSQL("ALTER TABLE user ADD COLUMN age INTEGER") } } // 构建数据库时添加迁移 Room.databaseBuilder( context, AppDatabase::class.java, "app-db" ) .addMigrations(MIGRATION_1_2) .build()
注意事项
- 数据兼容性:修改字段类型可能导致数据丢失(如
TEXT
转INTEGER
) - 事务处理:复杂迁移需包裹在
BEGIN TRANSACTION
和COMMIT
之间 - 备份机制:迁移前备份旧数据,防止回滚
云端数据迁移(Firebase/自建服务器)
场景说明
应用从本地存储切换至云端(如Firebase Realtime Database),或云端架构升级。
实现步骤
- 数据同步:将本地SQLite数据上传至云端
- 结构映射:调整云端数据结构与本地字段对应关系
- 增量更新:迁移后启用实时同步机制(如Firebase Sync)
代码示例(Firebase)
// 将SQLite数据导入Firebase fun migrateLocalToCloud(localData: List<User>) { val database = Firebase.database val usersRef = database.getReference("users") localData.forEach { user -> usersRef.child(user.id).setValue(user) } }
注意事项
- 网络可靠性:使用
WorkManager
确保迁移任务完成 - 冲突解决:合并本地与云端数据(如基于时间戳)
- 权限控制:云端数据需配置安全规则
版本升级数据迁移
场景说明
应用大版本更新时,旧数据结构与新功能不兼容(如新增功能依赖字段)。
实现方案
数据类型 | 迁移策略 |
---|---|
SharedPreferences | 使用commit 或apply 保存新键值,兼容旧版无该键的情况 |
文件存储 | 解析旧文件格式,转换为新格式后重新存储 |
数据库 | 结合Room 迁移或SQLite 的onUpgrade 处理 |
代码示例(SharedPreferences)
// 检查并迁移旧版偏好设置 val prefs = getSharedPreferences("app_prefs", MODE_PRIVATE) if (!prefs.contains("new_key")) { prefs.edit() .putString("new_key", prefs.getString("old_key", "default_value")) .remove("old_key") .apply() }
注意事项
- 版本标记:使用
SP
或数据库记录当前数据版本 - 灰度迁移:分批次迁移用户数据,降低风险
- 用户通知:重大迁移需提示用户并允许回滚
测试与调试
测试工具
- Android Studio Database Inspector:实时查看数据库变化
- Emulator不同API版本:测试低版本兼容性
- 单元测试:验证迁移逻辑(如JUnit+Robolectric)
调试技巧
- 日志打印:在
onUpgrade
或迁移函数中添加Log
- 条件断点:仅在特定版本迁移时触发断点
- 回滚机制:失败时执行
database.execSQL("ROLLBACK")
相关问题与解答
Q1:如何判断迁移是否成功?
A:
- 日志验证:在迁移逻辑末尾打印成功日志
- 数据校验:对比迁移前后关键数据(如计数、哈希值)
- 自动化测试:编写测试用例模拟升级流程
// 示例:验证用户表行数 val count = database.query("SELECT COUNT() FROM user").first() assert(count == expectedUserCount)
Q2:如何处理跨设备数据迁移?
A:
- 云端中转:将旧设备数据上传至服务器,新设备下载恢复
- 备份文件:生成加密备份文件(如JSON/Protobuf),通过存储或传输分享
- 直接传输:使用NFC/蓝牙/WiFi直连(适合小数据量)
// 导出SQLite为JSON文件 fun exportDatabase(context: Context): String { val db = SQLiteDatabase.openDatabase(...) val cursor = db.rawQuery("SELECT FROM user", null) return JSONObject(cursor).toString() // 需自定义序列化逻辑 }