# 音频缓存优化解决方案 ## 问题描述 在点击广告按钮时,发现会重复加载已经在游戏初始化时加载过的音效资源,导致以下问题: 1. **重复资源加载**:每次播放音效都会重新从Bundle加载资源 2. **性能影响**:不必要的资源加载消耗性能 3. **错误风险**:频繁的资源加载可能导致系统错误 ### 错误日志示例 ``` [BundleLoader] 从Bundle data 加载资源: 弹球音效/ui play index.js? [sm]:33 [BundleLoader] 资源加载成功: data/弹球音效/ui play index.js? [sm]:7 [AudioManager] 播放UI音效: data/弹球音效/ui play Error: SystemError (appServiceSDKScriptError) {"errMsg":"updateTextView:fail 33409 not found"} ``` ## 问题根源分析 ### 1. 触发链路 - 点击广告按钮 → 播放UI音效 `Audio.playUISound('data/弹球音效/ui play')` - 广告成功回调 → 触发奖励动画 → MoneyAni播放动画 → 播放获得金币音效 `Audio.playUISound('data/弹球音效/get money')` ### 2. 原始AudioManager问题 ```typescript // 每次播放都重新加载资源 const clip = await this.bundleLoader.loadAssetFromBundle('data', bundlePath, AudioClip); ``` ### 3. BundleLoader无缓存机制 BundleLoader的`loadAssetFromBundle`方法每次都会重新从Bundle加载资源,没有缓存机制。 ## 解决方案 ### 1. 音频缓存机制 在AudioManager中添加音频缓存: ```typescript // 音频缓存 private audioClipCache: Map = new Map(); private async playSound(audioSource: AudioSource, sfxPath: string, volume: number | undefined, baseVolume: number, soundType: string) { // 检查缓存中是否已有该音频 let clip = this.audioClipCache.get(cleanPath); if (!clip) { // 首次加载并缓存 clip = await this.bundleLoader.loadAssetFromBundle('data', bundlePath, AudioClip); this.audioClipCache.set(cleanPath, clip); console.log(`[AudioManager] 音效已缓存: ${cleanPath}`); } else { console.log(`[AudioManager] 使用缓存音效: ${cleanPath}`); } audioSource.playOneShot(clip); } ``` ### 2. 缓存管理方法 ```typescript // 清理缓存 public clearAudioCache() { console.log(`[AudioManager] 清理音频缓存,共${this.audioClipCache.size}个音效`); this.audioClipCache.clear(); } // 获取缓存信息 public getCacheInfo(): {count: number, paths: string[]} { return { count: this.audioClipCache.size, paths: Array.from(this.audioClipCache.keys()) }; } ``` ### 3. 静态方法支持 ```typescript // Audio静态类中添加缓存管理 static clearAudioCache() { const manager = AudioManager.getInstance(); if (manager) { manager.clearAudioCache(); } } static getCacheInfo(): {count: number, paths: string[]} { const manager = AudioManager.getInstance(); if (manager) { return manager.getCacheInfo(); } return {count: 0, paths: []}; } ``` ## 优化效果 ### 1. 性能提升 - **首次加载**:音效资源从Bundle加载并缓存 - **后续播放**:直接使用缓存,无需重复加载 - **减少I/O**:避免频繁的文件系统访问 ### 2. 稳定性提升 - **减少错误**:避免重复加载导致的系统错误 - **内存管理**:提供缓存清理机制,防止内存泄漏 ### 3. 调试支持 - **缓存状态**:可查看当前缓存的音效数量和路径 - **日志优化**:区分首次加载和缓存使用 ## 使用方法 ### 1. 正常使用(无需改动) ```typescript // 现有代码无需修改,自动享受缓存优化 Audio.playUISound('data/弹球音效/ui play'); Audio.playUISound('data/弹球音效/get money'); ``` ### 2. 缓存管理(可选) ```typescript // 查看缓存状态 const cacheInfo = Audio.getCacheInfo(); console.log(`缓存音效数量: ${cacheInfo.count}`); console.log(`缓存音效列表:`, cacheInfo.paths); // 清理缓存(在内存紧张时) Audio.clearAudioCache(); ``` ## 注意事项 1. **内存使用**:缓存会占用一定内存,但音效文件通常较小 2. **自动清理**:AudioManager销毁时会自动清理缓存 3. **向后兼容**:现有代码无需修改,自动享受优化 4. **调试信息**:控制台会显示缓存使用情况,便于调试 ## 测试验证 优化后的表现: - **首次播放**:`[AudioManager] 从Bundle加载新音效: 弹球音效/ui play` - **后续播放**:`[AudioManager] 使用缓存音效: data/弹球音效/ui play` - **无重复加载**:不再出现重复的Bundle加载日志 - **错误消除**:避免因重复加载导致的系统错误