Files
peko-ios/YuMi/Modules/YMRoom/View/AnimationView/BannerScheduler_README.md

7.1 KiB
Raw Blame History

BannerScheduler 使用说明

概述

BannerScheduler 是一个统一的 Banner 播放调度器,用于管理 V2 Banner 的播放队列和状态。它解决了原有代码中 Banner 队列管理分散、状态控制复杂的问题。

主要特性

1. 统一队列管理

  • 集中管理所有 V2 Banner 的播放队列
  • 自动处理队列的优先级排序
  • 支持队列的暂停、恢复、清空等操作

2. 智能优先级排序

  • 当前用户相关的 Banner 优先播放
  • 当前房间相关的 Banner 次优先播放
  • 其他 Banner 按队列顺序播放

3. 状态管理

  • 统一的播放状态控制
  • 防止多个 Banner 同时播放
  • 支持暂停和恢复功能

4. 代理模式

  • 通过代理模式解耦队列管理和播放逻辑
  • 支持播放开始、完成等事件回调
  • 便于进行单元测试和功能扩展

使用方法

1. 初始化

// 在 RoomAnimationView 中初始化
- (void)setupBanner {
    _roomBannertModelsQueueV2 = [NSMutableArray array];
    
    // 初始化 Banner 调度器
    self.bannerScheduler = [[BannerScheduler alloc] initWithDelegate:self];
}

2. 实现代理协议

@interface RoomAnimationView () <BannerSchedulerDelegate>
// ... 其他协议
@end

@implementation RoomAnimationView

#pragma mark - BannerSchedulerDelegate

- (void)bannerScheduler:(BannerScheduler *)scheduler shouldPlayBanner:(id)banner {
    // 将 Banner 数据转换为 AttachmentModel 并播放
    if ([banner isKindOfClass:[AttachmentModel class]]) {
        AttachmentModel *attachment = (AttachmentModel *)banner;
        [self _playBannerWithAttachment:attachment];
    }
}

- (void)bannerSchedulerDidFinishPlaying:(BannerScheduler *)scheduler {
    // Banner 播放完成,可以在这里进行清理工作
    NSLog(@"🔄 BannerScheduler: Banner 播放完成");
}

- (void)bannerScheduler:(BannerScheduler *)scheduler didStartPlayingBanner:(id)banner {
    // Banner 开始播放
    NSLog(@"🔄 BannerScheduler: Banner 开始播放 - 类型: %@", [banner class]);
}

@end

3. 添加 Banner 到队列

// 替换原有的队列添加逻辑
- (void)inserBannerModelToQueue:(AttachmentModel *)obj {
    // 参数验证
    if (!obj || ![obj isKindOfClass:[AttachmentModel class]]) {
        NSLog(@"⚠️ 警告: inserBannerModelToQueue 接收到无效参数: %@", obj);
        return;
    }
    
    // 使用新的调度器
    [self.bannerScheduler enqueueBanner:obj];
}

4. 在 Banner 播放完成后通知调度器

- (void)playBroveBanner:(AttachmentModel *)obj {
    if (!obj.data) {
        self.isRoomBannerV2Displaying = NO;
        [self.bannerScheduler markBannerFinished]; // 通知调度器播放完成
        return;
    }
    
    self.isRoomBannerV2Displaying = YES;
    @kWeakify(self);
    RoomInfoModel *roomInfo = self.hostDelegate.getRoomInfo;
    [BravoGiftBannerView display:self.bannerContainer
                       inRoomUid:roomInfo.uid
                            with:obj
                        complete:^{
        @kStrongify(self);
        NSLog(@"🔄 BravoGiftBannerView complete 回调被调用");
        self.isRoomBannerV2Displaying = NO;
        [self.bannerScheduler markBannerFinished]; // 通知调度器播放完成
    } exitCurrentRoom:^{
        @kStrongify(self);
        [self.hostDelegate exitRoom];
    }];
}

API 参考

主要方法

队列管理

  • enqueueBanner: - 添加 Banner 到播放队列
  • processNextBanner - 处理队列中的下一个 Banner
  • clearQueue - 清空播放队列
  • sortQueueByPriority - 根据优先级对队列进行排序

状态控制

  • pause - 暂停播放(保持队列状态)
  • resume - 恢复播放
  • markBannerFinished - 标记 Banner 播放完成

信息查询

  • isQueueEmpty - 检查队列是否为空
  • bannerAtIndex: - 获取队列中指定索引的 Banner
  • removeBannerAtIndex: - 移除队列中指定索引的 Banner
  • queueStatusDescription - 获取队列状态信息(用于调试)

属性

  • bannerQueue - Banner 播放队列(只读)
  • isPlaying - 当前是否正在播放 Banner只读
  • delegate - 调度器代理
  • queueCount - 队列中的 Banner 数量(只读)

迁移指南

从原有代码迁移

  1. 替换队列添加逻辑

    // 原有代码
    [self.roomBannertModelsQueueV2 addObject:obj];
    
    // 新代码
    [self.bannerScheduler enqueueBanner:obj];
    
  2. 替换播放完成回调

    // 原有代码
    [self processNextRoomEffectAttachment];
    
    // 新代码
    [self.bannerScheduler markBannerFinished];
    
  3. 移除原有的队列管理代码

    • 删除 roomBannertModelsQueueV2 属性
    • 删除 isRoomBannerV2Displaying 属性
    • 删除 processNextRoomEffectAttachment 方法
    • 删除 sortBannerQueue 方法

注意事项

  1. 类型安全BannerScheduler 使用 id 类型,在代理方法中需要进行类型检查
  2. 状态同步:原有的 isRoomBannerV2Displaying 状态仍然保留,用于向后兼容
  3. 错误处理:在 Banner 播放失败时,也要调用 markBannerFinished 通知调度器

性能优化

1. 队列长度控制

  • 建议设置最大队列长度,避免内存占用过多
  • 可以在 enqueueBanner: 方法中添加队列长度检查

2. 优先级计算优化

  • 当前的优先级计算在每次排序时都会执行
  • 可以考虑缓存优先级计算结果,减少重复计算

3. 内存管理

  • 确保在适当的时机调用 clearQueue 清空队列
  • 在 RoomAnimationView 销毁时清理调度器

扩展功能

1. 添加新的 Banner 类型

_playBannerWithAttachment: 方法中添加新的 case 分支:

case Custom_Message_Sub_New_Banner_Type:
    [self playNewBannerType:attachment];
    break;

2. 自定义优先级算法

修改 sortQueueByPriority 方法,添加自定义的优先级计算逻辑。

3. 添加队列监控

通过代理方法实现队列状态的实时监控和统计。

故障排除

常见问题

  1. Banner 不播放

    • 检查是否正确调用了 markBannerFinished
    • 检查代理方法是否正确实现
    • 查看控制台日志确认调度器状态
  2. 队列排序不正确

    • 检查 Banner 数据的 uidListroomUid 字段
    • 确认 AccountInfoStorage.instance.getUid 返回正确的用户ID
  3. 内存泄漏

    • 确保在适当的时机调用 clearQueue
    • 检查是否有循环引用

调试技巧

  1. 使用队列状态描述

    NSLog(@"队列状态: %@", [self.bannerScheduler queueStatusDescription]);
    
  2. 启用详细日志 在 BannerScheduler 中已经添加了详细的日志输出,可以通过控制台查看调度器的运行状态。

  3. 单元测试 创建模拟的 Banner 数据和代理对象,测试调度器的各种功能。

总结

BannerScheduler 通过统一的队列管理和状态控制,简化了 Banner 播放的复杂度,提高了代码的可维护性和可扩展性。通过合理的代理模式设计,保持了与现有代码的兼容性,同时为未来的功能扩展提供了良好的基础。