冥想呼吸助手:在 AR 眼镜上实现沉浸式呼吸引导
背景
作为一个长期伏案工作的程序员,我经常感到肩颈僵硬、精神紧张。之前尝试过一些冥想 App,但每次都要盯着手机屏幕,总觉得少了点什么------直到我接触了 Rokid AR 眼镜。
想象一下:你闭上眼睛,开始冥想,但又想看到呼吸节奏的引导。手机屏幕?太打扰了。智能手表?屏幕太小。AR 眼镜刚刚好,既能看到引导信息,又不会完全隔绝环境光。
于是,我开发了这款「冥想呼吸助手」。

技术选型
这次开发选择了 CXR-M SDK 而不是灵珠平台,主要考虑:
- 灵活性更高:CXR-M SDK 是纯 Android 开发,可以用熟悉的 Kotlin 和 Android Studio
- 实时交互:呼吸引导需要频繁更新显示内容,SDK 的流式传输能力正好满足
- TTS 语音 :呼吸阶段切换时需要语音提示,SDK 内置了 TTS 能力

技术方案
整体架构
采用简单的 MVC 架构,因为功能不复杂,没必要过度设计:

核心数据结构
冥想的核心是「呼吸模式」,我参考了一些心理学和呼吸疗法的资料,预设了 5 种常用模式:
enum class BreathingPattern(
val displayName: String,
val inhale: Int, // 吸气秒数
val hold: Int, // 屏息秒数
val exhale: Int, // 呼气秒数
val holdAfter: Int, // 呼后屏息秒数
val description: String
) {
RELAXING("放松呼吸", 4, 0, 4, 0, "简单有效的放松方式"),
BOX("箱式呼吸", 4, 4, 4, 4, "海军海豹队使用的减压法"),
FOUR_SEVEN_EIGHT("4-7-8呼吸", 4, 7, 8, 0, "帮助入睡的经典呼吸法"),
CALM("平静呼吸", 4, 2, 6, 0, "缓解焦虑情绪"),
DEEP("深度呼吸", 6, 2, 8, 2, "深度放松身心");
}
最常用的是 4-7-8 呼吸法,这是 Andrew Weil 医生推广的助眠技术,对缓解焦虑也很有效。
呼吸循环的实现
这是整个应用的核心逻辑,用 CountDownTimer 实现多阶段计时:
private enum class BreathingPhase {
INHALE, HOLD, EXHALE, HOLD_AFTER
}
private fun startPhaseTimer() {
val pattern = currentCourse?.pattern ?: return
// 根据当前阶段获取秒数
val seconds = when (currentPhase) {
BreathingPhase.INHALE -> pattern.inhale
BreathingPhase.HOLD -> pattern.hold
BreathingPhase.EXHALE -> pattern.exhale
BreathingPhase.HOLD_AFTER -> pattern.holdAfter
}
// 如果某阶段为0秒,直接跳过
if (seconds == 0) {
moveToNextPhase()
return
}
updatePhaseDisplay(currentPhase, seconds)
phaseTimer = object : CountDownTimer(seconds * 1000L, 1000) {
override fun onTick(millisUntilFinished: Long) {
phaseTimeLeft = (millisUntilFinished / 1000).toInt()
updatePhaseDisplay(currentPhase, phaseTimeLeft)
}
override fun onFinish() {
moveToNextPhase()
}
}.start()
}
private fun moveToNextPhase() {
currentPhase = when (currentPhase) {
BreathingPhase.INHALE -> if (pattern.hold > 0) HOLD else EXHALE
BreathingPhase.HOLD -> EXHALE
BreathingPhase.EXHALE -> if (pattern.holdAfter > 0) HOLD_AFTER else INHALE
BreathingPhase.HOLD_AFTER -> INHALE
}
// 语音提示当前阶段
val ttsText = when (currentPhase) {
BreathingPhase.INHALE -> "吸"
BreathingPhase.HOLD -> "屏"
BreathingPhase.EXHALE -> "呼"
BreathingPhase.HOLD_AFTER -> "屏"
}
RokidGlassesManager.sendTts(ttsText)
// 同步到眼镜
sendCurrentPhaseToGlasses()
startPhaseTimer()
}
这个实现有个细节:每个呼吸模式都有 4 个阶段,但有些阶段可能为 0(比如「放松呼吸」模式没有屏息阶段)。代码里做了判断,0 秒的阶段会自动跳过。
眼镜端显示格式
发送到眼镜的内容需要精心设计,信息要清晰但不杂乱:
🧘 快速放松
吸气
3 秒
⏱ 2:45 / 3:00
吸→屏→呼→屏
4 0 4 0
上面的区域显示课程名和当前阶段,中间是倒计时,下面是呼吸模式参数。用户一眼就能看清楚自己该怎么呼吸。
生成这个格式的代码:
private fun sendCurrentPhaseToGlasses() {
val course = currentCourse ?: return
val pattern = course.pattern
val phaseName = when (currentPhase) {
BreathingPhase.INHALE -> "吸气"
BreathingPhase.HOLD -> "屏息"
BreathingPhase.EXHALE -> "呼气"
BreathingPhase.HOLD_AFTER -> "屏息"
}
val text = buildString {
appendLine("🧘 ${course.name}")
appendLine()
appendLine(" $phaseName")
appendLine(" $phaseTimeLeft 秒")
appendLine()
val minutes = totalSecondsLeft / 60
val seconds = totalSecondsLeft % 60
appendLine("⏱ ${String.format("%d:%02d", minutes, seconds)} / ${course.durationMinutes}:00")
appendLine()
appendLine("吸→屏→呼→屏")
appendLine("${pattern.inhale} ${pattern.hold} ${pattern.exhale} ${pattern.holdAfter}")
}
RokidGlassesManager.sendBreathingGuide(text)
}
开发过程中的问题
问题一:Timer 的生命周期管理
一开始没有在 Activity 销毁时取消 Timer,导致切换课程时会有多个 Timer 同时运行,界面显示混乱。
解决方案:在 onDestroy() 中取消所有 Timer:
override fun onDestroy() {
super.onDestroy()
phaseTimer?.cancel()
totalTimer?.cancel()
}
问题二:暂停/继续功能
用户可能中途需要暂停,但 CountDownTimer 没有暂停方法,只能取消。
解决方案:记录当前剩余时间,暂停时取消 Timer,继续时用剩余时间重新创建 Timer:
private fun pauseMeditation() {
isPaused = true
phaseTimer?.cancel()
totalTimer?.cancel()
binding.btnStart.text = "继续"
}
private fun resumeMeditation() {
isPaused = false
startTotalTimer() // 用剩余时间重建
startPhaseTimer()
binding.btnStart.text = "暂停"
}
问题三:TTS 语音重叠
阶段切换很快时,TTS 语音可能会重叠播放。
目前的处理是保持简单,因为呼吸节奏通常不会太快(每个阶段至少 2 秒)。如果后续优化,可以考虑用队列管理 TTS 播放。
最终效果
功能清单
● 5 种呼吸模式 :放松呼吸、箱式呼吸、4-7-8 呼吸、平静呼吸、深度呼吸
● 5 种冥想课程 :快速放松(3分钟)、睡前放松(5分钟)、深度放松(10分钟)、专注力训练(5分钟)、缓解焦虑(3分钟)
● 实时眼镜同步 :呼吸阶段、倒计时、进度实时显示在眼镜上
● 语音引导 :每个阶段切换时语音提示「吸」「屏」「呼」
● 统计功能:今日冥想次数、累计时长、连续打卡天数
使用流程
- 打开 App,选择冥想类型和课程
- 连接 Rokid 眼镜
- 点击「开始冥想」
- 跟随眼镜上的引导呼吸
- 完成后查看统计数据
眼镜端效果
冥想进行中:
🧘 睡前放松
吸气
2 秒
⏱ 3:42 / 5:00
吸→屏→呼→屏
4 7 8 0
完成后:
完成后:
🎉 练习完成
今日冥想:1次
累计时长:8分钟
连续打卡:3天 🔥
💪 坚持练习,效果更好!
总结
项目亮点
- 沉浸式体验:眼镜显示呼吸引导,不需要盯着手机,更容易进入冥想状态
- 科学的呼吸模式:预设了多种经过验证的呼吸方法,不是随便设计的
- 简单易用:选择课程 → 开始 → 跟着呼吸,三步搞定
- 语音引导:闭上眼睛也能知道什么时候该吸气、呼气
不足与改进方向
- 缺少背景音乐:冥想时配合舒缓的音乐效果更好,后续可以加入
- 统计功能简单:目前只用了 SharedPreferences,数据多了可能需要用 Room 数据库
- 连续打卡计算:目前的打卡天数计算比较简单,没有处理跨日期的情况
- 可视化呼吸圆圈:手机端有个呼吸圆圈动画,但效果还可以更精致
总的来说,这是一个小而美的应用,解决了一个具体的问题。AR 眼镜在健康类应用上有天然优势,因为可以做到「看得到但不会被打扰」,非常适合冥想、运动这类场景。
项目地址 :MeditationHelper/
开发环境:
● Android Studio Hedgehog
● Kotlin 1.9.0
● CXR-M SDK 1.0.1
据多了可能需要用 Room 数据库
-
连续打卡计算:目前的打卡天数计算比较简单,没有处理跨日期的情况
-
可视化呼吸圆圈:手机端有个呼吸圆圈动画,但效果还可以更精致
总的来说,这是一个小而美的应用,解决了一个具体的问题。AR 眼镜在健康类应用上有天然优势,因为可以做到「看得到但不会被打扰」,非常适合冥想、运动这类场景。
项目地址 :MeditationHelper/
开发环境:
● Android Studio Hedgehog
● Kotlin 1.9.0
● CXR-M SDK 1.0.1
● minSdk 28 (Android 9.0)