问题清单与已知限制

概述

本文档记录 RunAdvisor 应用开发过程中发现的已知问题、已修复的 Bug 及当前仍存在的限制。每个问题包含问题描述、影响范围、修复状态和临时解决方案。

已修复问题

[FIXED] Canvas 时序 Bug - aboutToAppear 读取 width/height 为 0

问题编号: BUG-001

严重程度: 高

描述: Canvas 组件的 aboutToAppear 生命周期回调在 onReady 之前执行。若在 aboutToAppear 中读取 canvasContext.widthcanvasContext.height,将得到 0 值,导致 drawRouteMap() 中所有坐标计算失败,地图无法渲染。

影响范围: 路线地图页面,所有三条路线的地图均无法显示。

根本原因: ArkUI 的 Canvas 组件在 aboutToAppear 阶段尚未完成布局测量,此时 width/height 属性值为默认的 0。

修复方案: 将地图绘制触发时机从 aboutToAppear 移至 Canvas 的 onReady 回调,并在 drawRouteMap() 中实时读取 ctx.width/ctx.height

Canvas(this.mapCanvas)
  .width('100%')
  .height(320)
  .onReady(() => {
    this.mapRouteType = routeType;
    this.currentMapRoute = RouteService.getInstance().getRouteByType(routeType);
    this.drawRouteMap();
  })
private drawRouteMap(): void {
  const ctx: CanvasRenderingContext2D = this.mapCanvas;
  const canvasW: number = ctx.width;
  const canvasH: number = ctx.height;
  if (canvasW <= 0 || canvasH <= 0) {
    return;
  }
  // ... 绘制逻辑
}

修复状态: 已修复

验证方法: 进入路线详情页面,确认地图正常渲染,路线折线和地标标注可见。

未修复问题

[UNFIXED] 天气 API Key 为占位符

问题编号: BUG-002

严重程度: 中

描述: Constants.WEATHER_API_KEY 的值为占位字符串 'YOUR_KEY',无法调用 OpenWeatherMap API 获取真实天气数据。

static readonly WEATHER_API_KEY: string = 'YOUR_KEY';

影响范围: 天气功能完全不可用,首页天气卡片始终显示默认天气数据。

降级行为: WeatherService 在请求失败后自动返回默认天气数据:

getDefaultWeather(): WeatherInfo {
  return WeatherInfo.create(22, 20, 55, 3, '晴', '01d', '北京');
}

临时方案: 用户需替换 Constants.WEATHER_API_KEY 为有效的 OpenWeatherMap API Key。

修复建议:

  1. 申请有效的 OpenWeatherMap API Key 并替换
  2. 或搭建后端代理服务隐藏 API Key
  3. 或切换到免费天气 API(如和风天气免费版)

[UNFIXED] StepService 传感器在模拟器上返回 0

问题编号: BUG-003

严重程度: 低

描述: sensor.once(sensor.SensorId.PEDOMETER) 在模拟器上调用后可能返回步数为 0,因为模拟器没有物理计步器传感器。

private querySensorSteps(): Promise<number> {
  return new Promise((resolve: (value: number) => void) => {
    try {
      sensor.once(sensor.SensorId.PEDOMETER, (data: sensor.PedometerResponse) => {
        resolve(data.steps);
      });
    } catch (e) {
      resolve(0);
    }
    setTimeout(() => { resolve(0); }, 3000);
  });
}

影响范围: 模拟器上首页步数始终显示 0。真机上功能正常。

降级行为: StepService 优先读取 Preferences 中的缓存步数,仅缓存为 0 时才查询传感器:

async getStepCount(): Promise<number> {
  const prefs: PreferencesService = PreferencesService.getInstance();
  const saved: number = prefs.getStepCount();
  if (saved > 0) {
    this.currentSteps = saved;
    return saved;
  }
  const steps: number = await this.querySensorSteps();
  // ...
}

临时方案: 在模拟器上测试时,可通过手动调用 StepService.setSteps() 模拟步数数据。

[UNFIXED] 陀螺仪权限在模拟器上不可用

问题编号: BUG-004

严重程度: 低

描述: ohos.permission.GYROSCOPE 权限在模拟器上可能无法授予,导致 sensor.on(sensor.SensorId.GYROSCOPE) 调用抛出异常。

startGyroscope(): void {
  try {
    sensor.on(sensor.SensorId.GYROSCOPE, (data: sensor.GyroscopeResponse) => {
      this.lastGyroX = data.x;
      this.lastGyroY = data.y;
      this.gyroAvailable = true;
    }, { interval: 100000000 });
    this.listening = true;
  } catch (e) {
    this.gyroAvailable = false;
  }
}

影响范围: 模拟器上卡尔曼滤波位置增强功能不可用,enhance() 直接返回原始 GPS 坐标。真机上功能正常。

降级行为: gyroAvailable = false 时,enhance() 方法跳过卡尔曼滤波计算:

if (!this.gyroAvailable) {
  this.enhancedLat = rawLat;
  this.enhancedLng = rawLng;
  return [rawLat, rawLng];
}

临时方案: 无需处理,降级后应用其他功能正常。

[UNFIXED] 签名配置未完成

问题编号: BUG-005

严重程度: 高(仅影响真机部署)

描述: 项目未配置 HarmonyOS 应用签名,无法在真机上安装和运行应用。

影响范围: 无法将应用推送到真机设备,仅能在模拟器上运行。

临时方案: 在 DevEco Studio 中手动配置签名:

  1. 打开 File > Project Structure > Project > Signing Configs
  2. 勾选 Automatically generate signature
  3. 或手动指定证书和 Profile 文件

[UNFIXED] ‘app_name’ 字符串资源冲突警告

问题编号: BUG-006

严重程度: 低

描述: 编译时可能出现 app_name 字符串资源与 HarmonyOS 系统资源名称冲突的警告。

影响范围: 仅编译警告,不影响运行。

临时方案: 将 app_name 重命名为项目特定的名称,如 run_advisor_app_name

[UNFIXED] WeatherService 缓存逻辑错误

问题编号: BUG-007

严重程度: 中

描述: WeatherService 的缓存读写逻辑存在错误,cacheWeather()getCachedWeather() 使用了错误的 Preferences 键(调用了 saveStepCount/getStepCount 而非专用的天气缓存键)。

private getCachedWeather(): WeatherInfo | undefined {
  try {
    const prefs: PreferencesService = PreferencesService.getInstance();
    const cacheTime: number = prefs.getStepCount();  // 错误: 使用了步数键
    // ...
  } catch (e) {}
  return undefined;
}

private cacheWeather(info: WeatherInfo): void {
  try {
    const prefs: PreferencesService = PreferencesService.getInstance();
    prefs.saveStepCount(0);  // 错误: 覆盖了步数数据
  } catch (e) {}
}

影响范围:

  1. 天气缓存永远无法命中,每次都重新请求
  2. 缓存写入会清零步数数据

临时方案: 由于 API Key 为占位符,天气请求始终失败并返回默认数据,此 Bug 的实际影响被掩盖。修复 API Key 后需同时修复此缓存逻辑。

修复建议: 使用 WEATHER_CACHE_KEYWEATHER_CACHE_TIME_KEY 专用键存储天气缓存数据,并序列化 WeatherInfo 对象。

已知限制

模拟器功能限制

功能 模拟器状态 说明
天气数据 降级 API Key 未配置,使用默认数据
步数统计 降级 传感器返回0,使用缓存值
陀螺仪增强 不可用 传感器不可用,直接使用GPS原始值
GPS定位 降级 返回北京默认坐标
地图渲染 正常 Canvas渲染不依赖传感器
饮食记录 正常 本地存储,无外部依赖
跑步建议 降级 基于默认天气数据计算

功能限制

  1. 路线数据固定: 三条路线硬编码在 RouteService 中,无法动态加载或用户自定义
  2. 地标标注固定: 9个北京地标硬编码,不随城市变化
  3. 食物数据库固定: CalorieService 中的90种食物硬编码,无法扩展
  4. 无后台追踪: 应用不支持后台持续位置追踪和跑步记录
  5. 无社交功能: 不支持跑步数据分享和好友互动
  6. 单用户模式: 不支持多用户切换,所有数据存储在同一 Preferences 实例中

UI 限制

  1. 无深色模式: 当前仅支持浅色主题,未适配深色模式
  2. 无国际化: 界面文字全部硬编码为中文,不支持多语言
  3. 无平板适配: 界面布局针对手机屏幕设计,平板上未做特殊适配
  4. 无手势操作: 地图不支持拖拽、缩放手势

数据限制

  1. 无云端同步: 所有数据存储在本地 Preferences,卸载应用即丢失
  2. 无历史数据: 步数和饮食记录仅保留当天数据
  3. 天气缓存失效: 由于缓存逻辑 Bug,天气数据无法有效缓存

问题修复优先级建议

优先级 问题 理由
P0 BUG-005 签名配置 阻塞真机测试
P1 BUG-002 API Key 核心功能不可用
P1 BUG-007 缓存逻辑 数据正确性受影响
P2 BUG-003 模拟器步数 影响开发测试体验
P2 BUG-004 模拟器陀螺仪 影响开发测试体验
P3 BUG-006 资源命名 仅编译警告

测试覆盖缺口

  1. 无自动化测试框架,所有测试为手动执行
  2. 无 UI 自动化测试
  3. 无传感器模拟测试
  4. 无网络异常模拟测试
  5. 无并发数据访问测试

已修复问题补充

[FIXED] FoodInputDialog 布局 Bug - position + zIndex 导致遮罩异常

问题编号: BUG-008

严重程度: 中

描述: FoodInputDialog(饮食记录输入弹窗)使用 position({x:0, y:0}) + zIndex(999) 实现全屏遮罩效果,但在某些布局容器中 position 定位参考点不确定,导致遮罩层偏移或无法覆盖整个屏幕。

// 问题代码
Column() {
  // ... 弹窗内容
}
.position({ x: 0, y: 0 })
.zIndex(999)
.width('100%')
.height('100%')
.backgroundColor('rgba(0,0,0,0.5)')

根本原因: position() 的定位参考点为父容器的左上角,当父容器不是全屏时,position({x:0, y:0}) 仅覆盖父容器区域。在 Tabs + TabContent 的嵌套结构中,父容器高度可能不等于屏幕高度。

修复方案: 使用 Stack 容器替代 position + zIndex,Stack 的子组件自动层叠:

Stack() {
  // 原有页面内容
  
  if (this.showFoodDialog) {
    Column() {
      // 弹窗内容
    }
    .width('100%')
    .height('100%')
    .backgroundColor('rgba(0,0,0,0.5)')
  }
}

Stack 方案的优势:子组件按声明顺序从底到顶层叠,无需手动管理 zIndex;覆盖范围始终为 Stack 的完整区域,不受父容器布局影响。

修复状态: 已修复

[FIXED] build() 中 const 声明导致 ArkTS 编译错误

问题编号: BUG-009

严重程度: 高

描述: 在 build() 方法内使用 const 声明局部变量时,ArkTS 编译器报错 “Only UI component syntax is allowed in build”。

// 问题代码
build() {
  const bmi: number = this.getBMI();  // 编译错误
  const category: string = this.getBMICategory();  // 编译错误
  Column() { ... }
}

根本原因: ArkTS 严格模式对 build() 方法有特殊限制,仅允许 UI 组件语法,不允许声明 const/let 变量。这是 ArkTS 与标准 TypeScript 的重要差异之一。

修复方案: 将计算逻辑移到方法外部,使用 @State 或 get 方法替代:

// 方案一:使用 get 方法
private getBMI(): number {
  const heightM: number = this.profile.height / 100;
  return heightM > 0 ? this.profile.weight / (heightM * heightM) : 0;
}

// 在 build() 中调用
Text(this.getBMI().toFixed(1))
// 方案二:使用 @State 缓存(当值需要在多处使用时)
@State bmiValue: number = 0;

aboutToAppear() {
  this.bmiValue = this.profile.weight / ((this.profile.height / 100) ** 2);
}

修复状态: 已修复

[FIXED] RunAdvice 模型缺少 description 字段

问题编号: BUG-010

严重程度: 中

描述: RunAdvice 数据模型最初只有 title 和 type 字段,缺少 description 字段,导致跑步建议页面无法显示建议的详细说明文字。

// 问题代码
class RunAdvice {
  title: string = '';
  type: string = '';
  // 缺少 description 字段
}

修复方案: 增加 description 字段并在建议生成逻辑中填充内容:

class RunAdvice {
  title: string = '';
  type: string = '';
  description: string = '';

  static create(title: string, type: string, description: string): RunAdvice {
    const advice: RunAdvice = new RunAdvice();
    advice.title = title;
    advice.type = type;
    advice.description = description;
    return advice;
  }
}

修复状态: 已修复

[FIXED] geoLocationManager.CurrentLocationRequest 构造方式错误

问题编号: BUG-011

严重程度: 中

描述: LocationService 中使用 new geoLocationManager.CurrentLocationRequest() 构造定位请求对象,但该 API 不支持 new 构造函数调用。

// 问题代码
const requestInfo = new geoLocationManager.CurrentLocationRequest();

修复方案: 改用对象字面量方式构造:

const requestInfo: geoLocationManager.CurrentLocationRequest = {
  priority: geoLocationManager.LocationRequestPriority.FIRST_FIX,
};

ArkTS 严格模式下,许多系统 API 的类型只支持对象字面量初始化,不支持 new 构造。这是 ArkTS 与 TypeScript 的又一重要差异。

修复状态: 已修复

[FIXED] WeatherService 缓存键名错误

问题编号: BUG-007 (已修复版本)

严重程度: 中

描述: 此问题在"未修复问题"部分已记录,但实际上已在后续开发中修复。修复内容为使用专用天气缓存键替代步数键。

修复方案:

// 修复前
private getCachedWeather(): WeatherInfo | undefined {
  const cacheTime: number = prefs.getStepCount();  // 错误
  // ...
}

// 修复后
private getCachedWeather(): WeatherInfo | undefined {
  const cacheTime: number = prefs.getWeatherCacheTime();  // 正确
  const cacheJson: string = prefs.getWeatherCache();      // 正确
  if (cacheJson && cacheTime > 0) {
    // 反序列化天气数据
    return WeatherInfo.fromJSON(cacheJson);
  }
  return undefined;
}

private cacheWeather(info: WeatherInfo): void {
  prefs.saveWeatherCache(JSON.stringify(info));
  prefs.saveWeatherCacheTime(Date.now());
}

PreferencesService 中增加了专用方法:

getWeatherCache(): string {
  return this.ensureStore().getSync(Constants.WEATHER_CACHE_KEY, '') as string;
}

saveWeatherCache(json: string): void {
  this.ensureStore().putSync(Constants.WEATHER_CACHE_KEY, json);
  this.ensureStore().flushSync();
}

getWeatherCacheTime(): number {
  return this.ensureStore().getSync(Constants.WEATHER_CACHE_TIME_KEY, 0) as number;
}

saveWeatherCacheTime(time: number): void {
  this.ensureStore().putSync(Constants.WEATHER_CACHE_TIME_KEY, time);
  this.ensureStore().flushSync();
}

修复状态: 已修复

架构级限制

单文件架构

所有业务逻辑和 UI 代码集中在 Index.ets 一个文件中(约 1300+ 行),带来以下问题:

  1. 可维护性差: 修改某个功能需要在 1300 行中定位相关代码
  2. 编译效率低: 修改任何部分都需要重新编译整个文件
  3. 协作困难: 多人无法同时编辑同一文件
  4. 复用困难: 服务和组件无法跨页面复用

理想架构应将代码拆分为:

  • services/ 目录:各 Service 类独立文件
  • models/ 目录:UserProfile, RouteInfo, WeatherInfo 等数据模型
  • pages/ 目录:各 Tab 页面和 NavDestination 页面
  • components/ 目录:可复用的 UI 组件

当前单文件架构的原因是开发初期的快速迭代需求,后续版本应逐步重构拆分。

无数据库支持

当前所有数据通过 Preferences (键值对) 存储,适用于简单场景,但存在以下限制:

  1. 查询能力弱: 无法按条件查询数据(如查询某日期的饮食记录)
  2. 关系数据不支持: 无法建立数据间的关联关系
  3. 大数据量性能差: 饮食记录增长后,序列化/反序列化开销增大
  4. 无事务支持: 多个键的写入不是原子操作

HarmonyOS 提供了关系型数据库 (@kit.ArkData) 和分布式数据服务,后续版本可引入用于存储历史记录和饮食日志。

无后台服务

应用不支持后台持续运行,导致以下功能缺失:

  1. 实时跑步追踪: 无法在后台记录 GPS 轨迹和跑步数据
  2. 自动计步: 应用退到后台后无法持续计步
  3. 定时提醒: 无法在后台定时推送运动提醒
  4. 数据同步: 无法在后台自动同步数据

实现后台服务需要使用 BackgroundTaskManager 和 ContinuousTask,同时需要声明 KEEP_BACKGROUND_RUNNING 权限。

开发环境限制

DevEco Studio 版本依赖

RunAdvisor 基于 HarmonyOS 6.1.1 (API 24) 开发,DevEco Studio 版本需匹配:

组件 最低版本 当前使用版本
DevEco Studio 5.0.3 5.0.3+
HarmonyOS SDK API 24 API 24
ArkTS 严格模式 严格模式
hvigor 4.0 4.0+

构建警告

当前构建产生两个警告:

  1. GYROSCOPE 权限警告: 提醒 user_grant 权限需运行时请求,已在代码中处理
  2. 签名跳过警告: Will skip sign ‘hos_hap’,需配置签名后消除

两个警告均不影响模拟器调试,但在真机部署前需解决签名问题。

模拟器能力矩阵

功能 模拟器 真机 差异说明
天气查询 降级(默认数据) 正常(API Key配置后) 网络请求可用但Key为占位符
GPS定位 降级(北京默认) 正常 模拟器无GPS硬件
计步器 不可用(返回0) 正常 模拟器无计步传感器
陀螺仪 不可用 正常 模拟器无陀螺仪
地图渲染 正常 正常 Canvas不依赖硬件
饮食记录 正常 正常 纯本地功能
路线推荐 正常 正常 硬编码数据
资料设置 正常 正常 纯本地功能

问题复现步骤

BUG-002 天气 API Key 占位符

  1. 启动应用,进入首页
  2. 观察天气卡片区域
  3. 预期:显示当前真实天气;实际:始终显示"北京 22°C 晴"
  4. 检查 hilog 输出,可见天气 API 请求失败日志

BUG-003 模拟器步数为0

  1. 在模拟器上启动应用
  2. 进入首页,观察步数显示
  3. 预期:显示非零步数;实际:显示 0
  4. 真机上测试可见正常步数

BUG-004 模拟器陀螺仪不可用

  1. 在模拟器上启动应用
  2. 检查 hilog 输出
  3. 可见 “LocationEnhanceService: gyroscope not available” 警告
  4. enhance() 直接返回 GPS 原始坐标,无滤波效果

BUG-005 签名配置缺失

  1. 执行 build_project --product default
  2. 构建输出中出现 “Will skip sign ‘hos_hap’” 警告
  3. 尝试 start_app 推送到真机
  4. 安装失败,提示签名错误

BUG-008 FoodInputDialog 布局 (已修复)

  1. 进入饮食页面
  2. 点击添加食物按钮
  3. 弹窗应覆盖整个屏幕并显示半透明遮罩
  4. 修复前:遮罩可能偏移或尺寸异常;修复后:正常显示

BUG-009 build() const 声明 (已修复)

  1. 在 build() 方法内添加 const 声明
  2. 执行构建
  3. 编译错误:“Only UI component syntax is allowed in build”
  4. 将 const 移到方法外部后编译通过

问题修复历史

日期 问题 状态
初始 BUG-001 Canvas时序 已修复
初始 BUG-008 FoodInputDialog布局 已修复
初始 BUG-009 build() const 已修复
初始 BUG-010 RunAdvice缺字段 已修复
初始 BUG-011 CurrentLocationRequest 已修复
后续 BUG-007 缓存键名 已修复
待定 BUG-002 API Key 未修复
待定 BUG-003 模拟器步数 未修复(环境限制)
待定 BUG-004 模拟器陀螺仪 未修复(环境限制)
待定 BUG-005 签名配置 未修复(需手动配置)
待定 BUG-006 资源命名 未修复(仅警告)

后续改进建议

短期 (v1.1)

  1. 配置有效的天气 API Key 或搭建代理服务
  2. 在 DevEco Studio 中配置签名,支持真机部署
  3. 将 Index.ets 拆分为多个文件,改善可维护性
  4. 为 app_name 资源重命名避免冲突警告

中期 (v2.0)

  1. 引入关系型数据库存储历史记录
  2. 实现后台跑步追踪服务
  3. 支持用户自定义路线
  4. 实现深色模式适配
  5. 支持国际化 (中英文)

长期 (v3.0)

  1. 实现云端数据同步
  2. 增加社交功能(跑步数据分享)
  3. 支持更多城市路线
  4. 集成健康设备数据(智能手表等)
  5. 实现自适应卡尔曼滤波参数

调试指南

hilog 日志查看

通过 hdc 工具查看应用运行日志:

hdc shell hilog | grep RunAdvisor

关键日志标识:

  • PreferencesService: 数据存储操作日志
  • LocationEnhanceService: 位置增强和陀螺仪日志
  • WeatherService: 天气查询和缓存日志
  • StepService: 步数查询日志

常见问题排查

症状 可能原因 排查方法
天气始终默认 API Key 占位符 检查 Constants.WEATHER_API_KEY 值
步数为0 模拟器无传感器 在真机上测试或手动设置步数
地图空白 Canvas 时序问题 确认 onReady 回调正常触发
弹窗位置偏移 position 布局问题 确认已使用 Stack 方案
编译错误"Only UI" build() 中有 const 将变量移到方法外部
真机安装失败 未配置签名 在 DevEco Studio 中配置签名
位置增强无效 陀螺仪不可用 检查 hilog 中陀螺仪警告
Logo

作为“人工智能6S店”的官方数字引擎,为AI开发者与企业提供一个覆盖软硬件全栈、一站式门户。

更多推荐