设计数据层实现高效数据共享
- Kotlin 多平台项目结构:
- 在 Kotlin 多平台项目中,创建
commonMain
源集,用于存放共享代码。这是利用 Kotlin 多平台项目结构的特性,将通用逻辑集中管理。
- 在
commonMain
中定义数据模型。例如,假设我们有一个简单的用户数据模型:
// commonMain/kotlin/com/example/shared/User.kt
package com.example.shared
data class User(
val id: String,
val name: String,
val email: String
)
- 数据持久化:
- 使用 SQLDelight:SQLDelight 是一个适用于 Kotlin 多平台的数据库框架。在
commonMain
中定义数据库模式和查询。
// commonMain/kotlin/com/example/shared/db/UserQueries.kt
package com.example.shared.db
import com.squareup.sqldelight.db.SqlDriver
import com.squareup.sqldelight.runtime.coroutines.asFlow
import com.squareup.sqldelight.runtime.coroutines.mapToList
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.map
interface UserQueries {
fun selectAllUsers(): Flow<List<User>>
fun insertUser(id: String, name: String, email: String)
}
actual class DatabaseDriverFactory {
actual fun createDriver(): SqlDriver {
// 实际实现会因平台而异,在 Android 上使用 AndroidSqliteDriver,在 iOS 上使用 NativeSqliteDriver
}
}
class UserDatabase(private val driver: SqlDriver) {
val userQueries: UserQueries = UserQueriesImpl(driver)
}
- **序列化/反序列化**:为了在不同平台间传输数据,使用 Kotlinx Serialization。在 `commonMain` 中添加依赖并为数据模型添加注解。
// commonMain/kotlin/com/example/shared/User.kt
package com.example.shared
import kotlinx.serialization.Serializable
@Serializable
data class User(
val id: String,
val name: String,
val email: String
)
- 这样就可以在不同平台上通过网络传输数据时,将 `User` 对象序列化为 JSON 等格式。
处理数据同步冲突
- 乐观锁:
- 在数据库表中添加版本号字段。例如,修改
User
表结构在 SQLDelight 中:
-- commonMain/resources/schema.sql
CREATE TABLE User (
id TEXT PRIMARY KEY,
name TEXT,
email TEXT,
version INTEGER DEFAULT 0
);
- 在更新数据时,先读取当前版本号,更新时带上版本号进行条件更新。如果版本号不一致则更新失败,需要重新读取数据后再更新。
// commonMain/kotlin/com/example/shared/db/UserQueries.kt
package com.example.shared.db
class UserQueriesImpl(driver: SqlDriver) : UserQueries {
override fun selectAllUsers(): Flow<List<User>> {
// 实现查询所有用户
}
override fun insertUser(id: String, name: String, email: String) {
// 实现插入用户
}
fun updateUser(id: String, name: String, email: String, expectedVersion: Int): Boolean {
val newVersion = expectedVersion + 1
val updatedRows = db.executeInsert(
"UPDATE User SET name =?, email =?, version =? WHERE id =? AND version =?",
name, email, newVersion, id, expectedVersion
)
return updatedRows > 0
}
}
- 合并策略:
- 如果出现冲突,制定合并策略。例如,以最后修改时间为准。可以在
User
数据模型中添加 lastModified
字段。
// commonMain/kotlin/com/example/shared/User.kt
package com.example.shared
import kotlinx.serialization.Serializable
import java.util.Date
@Serializable
data class User(
val id: String,
val name: String,
val email: String,
val lastModified: Date
)
- 在数据同步时,比较不同版本 `User` 对象的 `lastModified` 字段,保留最新修改的版本。
fun mergeUsers(localUser: User, remoteUser: User): User {
return if (localUser.lastModified.after(remoteUser.lastModified)) {
localUser
} else {
remoteUser
}
}
关键代码示例总结
- 共享数据模型:
@Serializable
data class User(
val id: String,
val name: String,
val email: String,
val lastModified: Date
)
- 数据库操作(以 SQLDelight 为例):
interface UserQueries {
fun selectAllUsers(): Flow<List<User>>
fun insertUser(id: String, name: String, email: String)
fun updateUser(id: String, name: String, email: String, expectedVersion: Int): Boolean
}
- 冲突处理(合并策略):
fun mergeUsers(localUser: User, remoteUser: User): User {
return if (localUser.lastModified.after(remoteUser.lastModified)) {
localUser
} else {
remoteUser
}
}