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

WearOS健身计数App:存储同步与MVVM架构实现咨询

问题解答:WearOS训练记录应用的存储、同步与MVVM架构整合

一、独立版/非独立版选择

你的判断完全合理,仅需同步整数计数的场景下,选独立版WearOS应用是最优解。独立版无需依赖手机即可运行,满足你“手表本地优先保存数据”的核心需求,同时也支持通过原生框架和手机交互同步。

二、存储与同步方案选型

1. 本地存储:Jetpack Datastore

用Jetpack Datastore(偏好型或Proto型)做手表本地存储非常合适,它比SharedPreferences更可靠,原生支持协程和Flow,能轻松处理按日期存储的动作计数这类结构化数据。

2. 跨设备同步方案对比

方案一:Wearable Data Layer API

  • 适用场景:仅需手表与配对手机之间同步数据,无多设备/跨账号同步需求
  • 实现思路:
    • 手表端更新计数后,先写入Datastore,再通过Data Layer将数据推送到配对手机
    • 手机端监听Data Layer的数据变化,同步到自身本地存储(如Room或Datastore)
    • 优势:无需额外云服务,依托Android原生框架,配对设备间同步延迟低,蓝牙连接时无网络也能同步
    • 劣势:仅支持配对设备间同步,设备未配对则无法同步

方案二:云存储(如Firebase Realtime Database、AWS Amplify)

  • 适用场景:需要多设备(多块手表、不同手机)同步,或希望数据长期云端备份
  • 实现思路:
    • 手表端写入Datastore后,通过云SDK将数据上传至云端
    • 手机端从云端拉取数据,同时监听云端变化实现实时同步
    • 优势:支持多设备跨场景同步,数据有云端备份
    • 劣势:需额外配置云服务,依赖网络连接,开发复杂度更高

更优方案推荐

如果核心需求只是手表与配对手机同步,优先选Wearable Data Layer API + Jetpack Datastore,开发成本低,符合Android原生体验;若未来有扩展多设备同步的需求,再引入云存储即可。

三、MVVM架构整合指导

核心分层逻辑

  1. Model层:
    • 封装Datastore的读写操作,提供Flow数据流供上层观察
    • 封装Data Layer或云存储的同步逻辑,作为数据同步的核心实现
  2. ViewModel层:
    • 持有Model层实例,处理UI触发的业务逻辑(增减计数、触发同步)
    • 将Model层的数据流转换为UI可观察的状态(如StateFlow)
  3. View层:
    • 实现+/-按钮和计数显示的布局
    • 监听ViewModel的状态变化更新UI,将用户操作传递给ViewModel

简化版代码示例

1. Model层:Datastore操作类

class WorkoutDataStore(private val context: Context) {
    private val dataStore = context.createDataStore(name = "workout_prefs")

    // 按日期存储训练数据,键格式为"workout_20250501_squat"
    suspend fun saveExerciseCount(date: String, exercise: String, count: Int) {
        dataStore.edit { prefs ->
            prefs["${date}_$exercise"] = count
        }
    }

    // 获取指定日期的所有训练数据
    fun getDailyWorkout(date: String): Flow<Map<String, Int>> {
        return dataStore.data.map { prefs ->
            listOf("squat", "deadlift", "bench press").associateWith { exercise ->
                prefs["${date}_$exercise"] ?: 0
            }
        }
    }
}

2. ViewModel层:业务逻辑处理

class WorkoutViewModel(private val dataStore: WorkoutDataStore) : ViewModel() {
    private val currentDate = "20250501" // 实际可通过Date工具类获取当前日期
    private val _dailyWorkout = MutableStateFlow<Map<String, Int>>(emptyMap())
    val dailyWorkout: StateFlow<Map<String, Int>> = _dailyWorkout

    init {
        viewModelScope.launch {
            dataStore.getDailyWorkout(currentDate).collect { workoutData ->
                _dailyWorkout.value = workoutData
            }
        }
    }

    fun incrementExercise(exercise: String) {
        viewModelScope.launch {
            val currentCount = _dailyWorkout.value[exercise] ?: 0
            dataStore.saveExerciseCount(currentDate, exercise, currentCount + 1)
            // 触发Data Layer同步逻辑,此处省略具体实现
        }
    }

    fun decrementExercise(exercise: String) {
        viewModelScope.launch {
            val currentCount = _dailyWorkout.value[exercise] ?: 0
            if (currentCount > 0) {
                dataStore.saveExerciseCount(currentDate, exercise, currentCount - 1)
                // 触发Data Layer同步逻辑,此处省略具体实现
            }
        }
    }
}

3. View层:WearOS Compose界面示例

@Composable
fun WorkoutScreen(viewModel: WorkoutViewModel = viewModel()) {
    val workoutData by viewModel.dailyWorkout.collectAsState()

    Column(
        modifier = Modifier.fillMaxSize(),
        horizontalAlignment = Alignment.CenterHorizontally,
        verticalArrangement = Arrangement.Center
    ) {
        workoutData.forEach { (exercise, count) ->
            ExerciseCounter(
                exerciseName = exercise,
                count = count,
                onIncrement = { viewModel.incrementExercise(exercise) },
                onDecrement = { viewModel.decrementExercise(exercise) }
            )
        }
    }
}

@Composable
fun ExerciseCounter(exerciseName: String, count: Int, onIncrement: () -> Unit, onDecrement: () -> Unit) {
    Row(
        modifier = Modifier.padding(12.dp),
        verticalAlignment = Alignment.CenterVertically,
        horizontalArrangement = Arrangement.SpaceAround
    ) {
        Text(text = exerciseName, fontSize = 18.sp)
        Button(onClick = onDecrement) { Text("-") }
        Text(text = count.toString(), fontSize = 22.sp, modifier = Modifier.padding(0.dp, 0.dp, 0.dp, 4.dp))
        Button(onClick = onIncrement) { Text("+") }
    }
}

四、简化版项目扩展说明

基于上述代码搭建基础项目后,需补充两个核心部分:

  • Data Layer同步逻辑:在ViewModel的saveExerciseCount方法后,通过Wearable.getDataClient(context)将数据发送到手机;手机端注册DataClient.OnDataChangedListener接收数据,同步到自身存储
  • 日期自动处理:用SimpleDateFormat或LocalDate自动生成当日日期,替代硬编码的20250501

内容的提问来源于stack exchange,提问作者theproductivepickle

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.13 20:23:10