重构马拉松运动状态交互,数字心动HarmonyOS 实况窗落地实战 原创
头像 s297165331 2026-05-18 17:47:39    发布
509 浏览 7 点赞 0 收藏

重构马拉松运动状态交互,数字心动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/

转载请注明出处



©本站发布的所有内容,包括但不限于文字、图片、音频、视频、图表、标志、标识、广告、商标、商号、域名、软件、程序等,除特别标明外,均来源于网络或用户投稿,版权归原作者或原出处所有。我们致力于保护原作者版权,若涉及版权问题,请及时联系我们进行处理。
分类
其它

暂无评论数据

加载中...

发布

头像

s297165331

我还没有写个人简介......

1

帖子

0

提问

24

粉丝

关注
热门推荐
地址:北京市朝阳区北三环东路三元桥曙光西里甲1号第三置业A座1508室 商务内容合作QQ:2291221 电话:13391790444或(010)62178877
版权所有:电脑商情信息服务集团 北京赢邦策略咨询有限责任公司
声明:本媒体部分图片、文章来源于网络,版权归原作者所有,我司致力于保护作者版权,如有侵权,请与我司联系删除

京ICP备:2022009079号-2

京公网安备:11010502051901号

ICP证:京B2-20230255