MST

星途 面试题库

面试题:Kotlin跨平台移动开发的数据共享与同步

在Kotlin跨平台移动开发项目里,不同平台(如Android和iOS)需要共享和同步一些数据。请阐述你会如何设计数据层,利用Kotlin的哪些特性来实现高效的数据共享,并且如何处理数据同步过程中可能出现的冲突,给出具体的实现思路和关键代码示例。
40.6万 热度难度
编程语言Kotlin

知识考点

AI 面试

面试题答案

一键面试

设计数据层实现高效数据共享

  1. 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
)
  1. 数据持久化
    • 使用 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 等格式。

处理数据同步冲突

  1. 乐观锁
    • 在数据库表中添加版本号字段。例如,修改 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
    }
}
  1. 合并策略
    • 如果出现冲突,制定合并策略。例如,以最后修改时间为准。可以在 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
    }
}

关键代码示例总结

  1. 共享数据模型
@Serializable
data class User(
    val id: String,
    val name: String,
    val email: String,
    val lastModified: Date
)
  1. 数据库操作(以 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
}
  1. 冲突处理(合并策略)
fun mergeUsers(localUser: User, remoteUser: User): User {
    return if (localUser.lastModified.after(remoteUser.lastModified)) {
        localUser
    } else {
        remoteUser
    }
}