s297165331 2026-05-18 17:47:39 发布重构马拉松运动状态交互,数字心动HarmonyOS 实况窗落地实战
用Live View Kit实况窗打造专业运动实时状态服务
作者:数字心动App鸿蒙版负责人史大伟
一、运动中的数据查看困境与数字心动的破局之道
1.1 关于数字心动
在开始聊技术之前,先介绍一下我们的主角——数字心动。
数字心动APP是中国田径协会官方认证的体育生态平台,深耕路跑垂直领域,以"让运动呈现无限可能"为愿景。平台业务矩阵丰富多元,涵盖线上赛、定制化各类主题线上赛、国际赛事&城市马拉松赛事及其他非路跑类赛事。
为了满足用户全周期参赛需求,数字心动打造了一站式服务体系:
l 赛前:提供报名通道、赛事日历、备赛训练计划、路线指引及装备补给采购服务
l 赛中:实时同步直播画面、运动轨迹,提供精准计时功能
l 赛后:支持成绩查询、电子证书生成、赛事影像留存、社交分享及时光轴回顾等服务
简单来说,数字心动就是跑者们的"全能运动管家",全方位服务赛事公司、企事业单位及广大跑者。
1.2 跑步场景的痛点分析
想象一下这个场景:你正在公园里挥汗如雨地跑步,突然想看看自己跑了多远、配速多少。于是你不得不停下脚步,掏出手机,解锁屏幕,找到数字心动APP,打开运动页面…等你看完数据重新跑起来,刚才那股"我要破PB(专业跑步术语,Personal Best个人最好成绩,简称PB)"的劲头早就泄了一半。
这就是传统运动APP的痛点:
l 频繁解锁手机:运动中掏出手机既危险又打断节奏
l 切换APP查看数据:注意力分散,运动体验大打折扣
l 传统方案局限:通知栏信息有限,悬浮窗侵入性强,亮屏耗电严重
根据《2023中国路跑赛事蓝皮书》中的数据,仍有30%的马拉松跑者未使用智能穿戴设备监测运动数据,以及随着全民健康热潮带动的新手和休闲跑人群,这些跑者们也需要的是一种"一瞥即得"的数据查看方式——不用掏手机、不用解锁、不用打开APP,运动数据就能实时呈现在眼前。
1.3 调研Live View Kit 实况窗
在调研了多种方案后,我们团队将目光投向了 HarmonyOS Live View Kit 实况窗。发现它完美契合了运动场景的核心需求:
| 特性 | 说明 |
| 系统级支持 | 无需额外权限,系统原生能力 |
| 轻量级展示 | 不占用过多系统资源 |
| 常驻显示 | 胶囊+卡片形态,随时可见 |
| 一瞥即得 | 关键信息一目了然 |
Live View Kit 实况窗支持三种形态:
1. 顶部状态栏胶囊:最小化显示,仅展示核心状态
2. 顶部卡片:展开后显示详细数据
3. 锁屏胶囊:锁屏状态下依然可见
这不正是运动场景需要的吗?跑者只需抬眼一瞥,运动时长、距离、配速等关键数据尽收眼底,全程无需掏出手机!
二、数字心动鸿蒙版 Live View Kit 实况窗开发实践
2.1 核心场景与展示内容
数字心动的实况窗主要服务于运动状态实时展示场景,需要呈现的内容包括:
l 运动状态:运动中 / 运动暂停中
l 运动时长:实时计时
l 运动距离:公里数
l 配速/时速:跑步看配速,骑行看时速

实况窗卡片展示

实况窗暂停状态
2.2 交互原则与规则
在设计实况窗交互时,我们遵循以下原则:
1. 信息优先级:状态 > 时长 > 距离 > 配速,核心信息优先展示
2. 状态切换:运动中与暂停状态有明显视觉区分
3. 实时更新:数据刷新频率合理,既保证实时性又不过度消耗资源
4. 生命周期管理:实况窗伴随用户整个运动生命周期,从开始到结束
2.3 关键开发思路分享
2.3.1 整体架构设计
数字心动采用 Flutter + HarmonyOS 原生的混合开发模式。实况窗的更新链路如下:
Flutter 运动页面 → MethodChannel → HarmonyOS 原生插件 → Live View Kit

实况窗胶囊形态
2.3.2 Flutter 侧实现
在 Flutter 侧,我们通过 SportManager 封装了与原生通信的接口:
// sport_manager.dart
// 启动实况窗
Future<dynamic> startLiveView({required String title, required String content}) async {
if (defaultTargetPlatform == TargetPlatform.ohos) {
final result = await _sportChannel.invokeMethod("startLiveView", {
"title": title,
"content": content
});
return result == true;
}
return true;
}
// 更新实况窗
Future<dynamic> updateLiveView({
String? title,
String? content,
String? firstTitle,
String? firstContent,
String? lastTitle,
String? lastContent
}) async {
if (defaultTargetPlatform == TargetPlatform.ohos) {
final result = await _sportChannel.invokeMethod("updateLiveView", {
"title": title,
"content": content,
"firstContent": firstContent,
"firstTitle": firstTitle,
"lastTitle": lastTitle,
"lastContent": lastContent,
});
return result == true;
}
return true;
}
// 停止实况窗
Future<dynamic> stopLiveView({String? title, String? content}) async {
if (defaultTargetPlatform == TargetPlatform.ohos) {
final result = await _sportChannel.invokeMethod("stopLiveView", {
"title": title,
"content": content
});
return result == true;
}
return true;
}
2.3.3 运动页面实时数据推送
在 sport_page.dart 中,我们通过定时器每秒更新实况窗数据:
// sport_page.dart
void initSportTimer() {
sportTimer = Timer.periodic(const Duration(seconds: 1), (timer) {
// ... 其他逻辑 ...
if (sportStatus.value == SportStatus.start) {
// 锁屏UI始终更新(无论前台后台)
if (defaultTargetPlatform == TargetPlatform.ohos) {
final distanceStr = (distanceNotifier.value / 1000).toStringAsFixed(2);
final paceStr = paceNotifier.value.toRunDataPaceValue(sportType: sportType);
SportManager.getInstance().updateLiveView(
title: getSportTitle(sportStatus.value),
content: "运动时长:${formatDurationForLiveView(currSportTime)}",
firstTitle: distanceStr,
firstContent: "公里",
lastTitle: paceStr,
lastContent: sportType == SportType.bicycle ? "时速" : "配速",
);
}
} else if (sportStatus.value == SportStatus.pause) {
int ptime = pauseWatchTimer.elapsedMilliseconds ~/ 1000;
// 锁屏UI始终更新(无论前台后台)
SportManager.getInstance().updateLiveView(
title: getSportTitle(sportStatus.value),
content: "暂停时长:${formatDurationForLiveView(ptime)}",
);
}
});
}
这里有个巧妙的设计:无论应用在前台还是后台,实况窗都会持续更新。这意味着即使用户切换到其他应用或锁屏,运动数据依然实时可见。
2.3.4 HarmonyOS 原生侧实现
在 HarmonyOS 侧,SportPlugin.ets 负责接收 Flutter 传来的数据并调用 Live View Kit:
// SportPlugin.ets
/**
* 启动直播视图
*/
private async startLiveView(call: MethodCall) {
try {
this.isProcessing = true;
let title: string = call.argument("title")
let content: string = call.argument("content")
const hasNext = await this.liveViewController.startLiveView(title, content);
Logger.info('live-view', '状态:启动直播视图 hasNext=', hasNext)
} catch (e) {
console.error(e);
} finally {
this.isProcessing = false;
}
}
/**
* 更新直播视图
*/
async updateLiveView(call: MethodCall, result: MethodResult): Promise<void> {
const title: string = call.argument("title")
const content: string = call.argument("content")
const firstTitle: string = call.argument("firstTitle")
const firstContent: string = call.argument("firstContent")
const lastTitle: string = call.argument("lastTitle")
const lastContent: string = call.argument("lastContent")
if (this.isProcessing) {
return
}
try {
this.isProcessing = true;
const hasNext = await this.liveViewController.updateLiveView(
title, content, firstTitle, firstContent, lastTitle, lastContent
);
Logger.info('live-view', '状态:更新直播视图 hasNext=', hasNext)
} finally {
this.isProcessing = false;
}
result.success(true)
}
/**
* 停止直播视图
*/
private stopLiveView = async (call: MethodCall) => {
if (this.isProcessing) {
return;
}
try {
this.isProcessing = true;
let title: string = call.argument("title")
let content: string = call.argument("content")
await this.liveViewController.stopLiveView(title, content);
Logger.info('live-view', '状态:停止直播视图');
} finally {
this.isProcessing = false;
}
}
2.3.5 防并发处理
注意到代码中的 isProcessing 标志了吗?这是一个防并发的设计:
if (this.isProcessing) {
return
}
由于实况窗更新频率较高(每秒一次),如果上一次更新还未完成,新的更新请求会被直接忽略。这避免了:
l 多次并发调用导致的资源竞争
l 数据展示错乱
l 系统性能问题
2.3.6 实时数据更新策略
我们的更新策略可以总结为:
| 场景 | 更新频率 | 更新内容 |
| 运动中 | 每秒 | 时长、距离、配速 |
| 暂停中 | 每秒 | 暂停时长 |
| 运动结束 | 一次 | 停止实况窗 |
2.3.7 信息优先级设计
实况窗的信息布局遵循"重要信息优先"原则:
┌─────────────────────────────────────┐
│ 户外跑 - 运动中 │ ← 状态(最重要)
│ 运动时长:00:18 │ ← 时长(次重要)
│ │
│ 0.00 公里 ······ 0'00" 配速 │ ← 距离 & 配速
└─────────────────────────────────────┘
l 标题区:运动类型 + 状态,让用户一眼知道当前在做什么
l 副标题区:运动时长,核心计时信息
l 数据区:左右分栏展示距离和配速,符合阅读习惯
2.3.8 状态切换逻辑
运动中与暂停状态的切换通过 sportStatus 状态机管理:
// 运动中
SportStatus.start → 显示"运动中" + 运动时长
// 暂停中
SportStatus.pause → 显示"运动暂停中" + 暂停时长

![实况窗状态切换演示]()
三、功能收益、经验总结与未来计划
3.1 功能收益
接入 Live View Kit 实况窗后,数字心动获得了以下收益:
1. 用户体验提升:跑者无需掏手机即可查看运动数据,运动体验更流畅
2. 安全性增强:减少运动中操作手机的频率,降低安全隐患
3. 电量优化:相比保持屏幕常亮,实况窗的功耗更低
4. 专业形象:系统级能力加持,彰显专业运动APP的品质
3.2 实现形态总览
数字心动的实况窗实现了三种形态,伴随用户的整个运动生命周期:
| 形态 | 场景 | 特点 |
| 顶部状态栏胶囊 | 运动中最小化 | 仅显示图标和时长,极简展示 |
| 顶部卡片 | 下拉通知栏 | 完整展示运动数据 |
| 锁屏胶囊 | 锁屏状态 | 无需解锁即可查看 |
3.3 开发经验总结
在开发过程中,我们总结了以下经验:
1. 防并发很重要:高频更新场景下,务必做好并发控制
2. 前后后台一致:实况窗的更新不应受应用前后台状态影响
3. 数据格式化:配速、时长等数据需要精心格式化,确保展示美观
4. 生命周期管理:运动结束时务必调用 stopLiveView,避免资源泄漏
5. 跨平台兼容:通过 defaultTargetPlatform 判断平台,确保非鸿蒙设备不受影响
在实况窗上架方面:
1. 需要给华为提供设计图,用于实况窗的上架。
2. 需要在华为应用市场提交实况窗申请,等待审核通过。
3. 实况窗在小胶囊状态下,文字不要写太多,避免审核不通过。
3.4 未来计划
实况窗的能力远不止于此!未来我们计划:
l 增加交互按钮:在实况窗卡片中增加"暂停/继续"、"结束运动"等快捷操作按钮,让用户无需打开APP即可控制运动状态
l 增加数据展示:在实况窗卡片中增加运动数据展示,如心率、步数等,为用户提供更丰富的运动信息。
四、给 HarmonyOS 开发者的建议
数字心动在运动场景中的探索,为 HarmonyOS 开发者提供了一个很有参考价值的实践样本。
我们的核心建议是:
凡是具有"持续状态变化 + 高频查看需求"的业务,都值得尝试 HarmonyOS 实况窗。
适用场景包括但不限于:
l 运动健身类APP
l 导航出行类APP
l 音乐播放类APP
l 外卖配送类APP
l 任何需要实时状态展示的场景
结语
从"掏手机看数据"到"抬眼即见",数字心动通过 HarmonyOS Live View Kit 实况窗,为跑者们带来了更专业、更便捷的运动体验。
如果你也是一名跑者,欢迎下载数字心动APP,体验实况窗带来的全新运动交互方式。让我们一起,让运动呈现无限可能!
数字心动官网:https://www.shuzixindong.com/
转载请注明出处
暂无评论数据
发布
相关推荐
星晨未来
795
0
三元桥的水冰兔
2054
0
s297165331
我还没有写个人简介......
帖子
提问
粉丝
京公网安备:11010502051901号