widget_fix_v2_summary.md 4.3 KB

桌面卡片更新机制修复 V2

问题分析

从日志分析发现的关键问题:

  1. "batch update completed for 0 widgets" - 批量更新时没有找到任何卡片
  2. 状态反复切换 - isPlaying在true/false之间快速切换
  3. 缺少全局监听器日志 - 没有看到全局监听器的设置消息
  4. 多实例问题 - 可能有多个FormExtensionAbility实例,每个都有自己的formSizeMap

根本原因

  1. 多实例冲突:多个FormExtensionAbility实例共享同一个全局监听器,但各自维护独立的formSizeMap
  2. 状态管理混乱:卡片删除后,某些实例的formSizeMap变空,但全局监听器仍在运行
  3. 重复更新:onUpdateForm中同时调用单个更新和批量更新

解决方案 V2

1. 创建全局卡片管理器

创建了 GlobalWidgetManager 来统一管理所有活跃卡片:

export class GlobalWidgetManager {
  private static instance: GlobalWidgetManager | null = null;
  private static activeWidgets: Map<string, WidgetSize> = new Map();

  // 注册卡片
  public registerWidget(formId: string, size: WidgetSize): void
  
  // 注销卡片
  public unregisterWidget(formId: string): void
  
  // 获取所有活跃卡片
  public getActiveWidgets(): Map<string, WidgetSize>
  
  // 获取活跃卡片数量
  public getActiveWidgetCount(): number
}

2. 修改EntryFormAbility

  • 移除本地formSizeMap:使用全局管理器替代
  • 统一卡片注册:在onAddForm中注册到全局管理器
  • 统一卡片注销:在onRemoveForm中从全局管理器注销
  • 全局状态检查:更新前检查全局活跃卡片数量

3. 关键修改点

A. 卡片注册

// 旧代码
this.formSizeMap.set(formId, widgetSize);

// 新代码
this.globalWidgetManager.registerWidget(formId, widgetSize);

B. 卡片注销

// 旧代码
this.formSizeMap.delete(formId);

// 新代码
this.globalWidgetManager.unregisterWidget(formId);

C. 全局监听器

private setupGlobalStateListener(): void {
  const avSessionListener = AvSessionWidgetListener.getInstance();
  avSessionListener.addStateListener((data: WidgetData) => {
    const activeWidgetCount = GlobalWidgetManager.getInstance().getActiveWidgetCount();
    hilog.info(0x0000, TAG, `Global listener received update: widgets count: ${activeWidgetCount}`);
    
    // 只有当有活跃卡片时才更新
    if (activeWidgetCount > 0) {
      this.updateAllWidgetsWithData(data);
    } else {
      hilog.info(0x0000, TAG, 'No active widgets, skipping update');
    }
  });
}

D. 批量更新

private updateAllWidgetsWithData(data: WidgetData): void {
  const activeWidgets = this.globalWidgetManager.getActiveWidgets();
  hilog.info(0x0000, TAG, `Batch update called, active widgets: ${activeWidgets.size}`);
  
  if (activeWidgets.size === 0) {
    hilog.warn(0x0000, TAG, 'No widgets to update');
    return;
  }
  
  // 更新所有活跃卡片...
}

预期效果

应该看到的改进:

  1. 正确的卡片计数:批量更新显示正确的卡片数量,不再是0
  2. 全局监听器日志:看到 "global state listener setup successfully" 消息
  3. 状态同步:所有卡片状态保持一致,不再反复切换
  4. 清晰的日志:每次更新都显示正确的活跃卡片数量

不应该再看到的问题:

  • ❌ "batch update completed for 0 widgets"
  • ❌ 状态在true/false之间快速无序切换
  • ❌ 卡片删除后仍然尝试更新的错误

测试要点

  1. 启动测试:启动应用,确认看到全局监听器设置消息
  2. 卡片管理:添加/删除卡片,观察全局管理器的注册/注销日志
  3. 状态同步:播放/暂停音乐,确认所有卡片同步更新
  4. 批量更新:确认批量更新显示正确的卡片数量
  5. 多卡片测试:添加多个卡片,确认都能正常工作

架构改进

  1. 单一数据源:所有卡片信息统一由GlobalWidgetManager管理
  2. 实例隔离:多个FormExtensionAbility实例不再相互干扰
  3. 状态一致性:全局状态确保所有卡片保持同步
  4. 资源管理:更好的卡片生命周期管理,避免内存泄漏

这个修复应该彻底解决卡片更新的问题,提供更稳定和一致的用户体验。