# 播放上一首问题修复 ## 问题描述 用户点击"播放上一首"按钮时,虽然播放列表显示有上一首歌曲(`hasNext=true, hasPrevious=true, totalCount=101`),但实际播放的却是下一首歌曲。 ## 问题分析 ### 日志分析 从日志中可以看到以下异常流程: 1. 用户点击"播放上一首" 2. 系统正确识别有上一首歌曲可播放 3. 但随即触发了 `Playback completed` 事件 4. 这导致自动播放逻辑启动,播放了下一首歌曲而不是上一首 ### 根本原因 问题出现在歌曲切换的时序上: 1. `playPrevious()` 调用 `stopSilently()` 停止当前播放 2. 然后调用 `playNewSongDirectly()` 开始播放新歌曲 3. 但是停止播放器时触发的 `onPlaybackCompleted` 回调仍然会被执行 4. 这个回调触发了自动播放逻辑 `handleAutoPlayOnCompletion()` 5. 自动播放逻辑在顺序播放模式下会播放下一首歌曲 6. 结果就是用户想要的上一首歌曲被自动播放的下一首歌曲覆盖了 ### 竞态条件 这是一个典型的竞态条件问题: - 手动歌曲切换操作(playPrevious/playNext) - 自动播放逻辑(onPlaybackCompleted 触发的 handleAutoPlayOnCompletion) 两者同时执行,导致预期外的行为。 ## 修复方案 ### 1. 添加手动切换标志 在 `UnifiedPlayerService` 中添加一个标志来标识当前是否正在进行手动歌曲切换: ```typescript private isManualSongChange: boolean = false; // 新增:是否正在进行手动歌曲切换 ``` ### 2. 在手动切换方法中设置标志 在 `playNext()`、`playPrevious()` 和 `playSongAtIndex()` 方法中: ```typescript async playPrevious(): Promise { try { // 设置手动歌曲切换标志,防止自动播放干扰 this.isManualSongChange = true; // ... 原有逻辑 ... } catch (error) { await this.handlePlaybackError(error as Error, PlayerErrorType.PLAYBACK_ERROR); } finally { // 确保在任何情况下都清除手动切换标志 setTimeout(() => { this.isManualSongChange = false; }, 1000); // 延迟1秒清除,确保播放器状态稳定 } } ``` ### 3. 在自动播放逻辑中检查标志 在 `handleAutoPlayOnCompletion()` 方法开头添加检查: ```typescript private async handleAutoPlayOnCompletion(): Promise { try { // 检查是否正在进行手动歌曲切换,如果是则跳过自动播放 if (this.isManualSongChange) { LogUtils.getInstance().LOGI('UnifiedPlayerService: Manual song change in progress, skipping auto-play'); return; } // ... 原有的自动播放逻辑 ... } } ``` ## 修复效果 ### 修复前的流程 1. 用户点击"上一首" → `playPrevious()` 2. `stopSilently()` 停止当前播放 3. `playNewSongDirectly()` 开始播放上一首 4. **问题**:`onPlaybackCompleted()` 被触发(来自刚停止的歌曲) 5. `handleAutoPlayOnCompletion()` 执行自动播放逻辑 6. 结果:播放了下一首歌曲(覆盖了上一首) ### 修复后的流程 1. 用户点击"上一首" → `playPrevious()` 2. 设置 `isManualSongChange = true` 3. `stopSilently()` 停止当前播放 4. `playNewSongDirectly()` 开始播放上一首 5. `onPlaybackCompleted()` 被触发(来自刚停止的歌曲) 6. `handleAutoPlayOnCompletion()` 检查到 `isManualSongChange = true`,跳过自动播放 7. 1秒后清除 `isManualSongChange` 标志 8. 结果:正确播放上一首歌曲 ## 相关方法 - `playNext()` - 播放下一首 - `playPrevious()` - 播放上一首 - `playSongAtIndex()` - 播放指定索引歌曲 - `handleAutoPlayOnCompletion()` - 自动播放逻辑 ## 测试验证 修复后需要验证: 1. 点击"上一首"按钮能正确播放上一首歌曲 2. 点击"下一首"按钮能正确播放下一首歌曲 3. 歌曲自然播放完成后的自动播放功能仍然正常工作 4. 各种播放模式(顺序、随机、单曲循环等)下的切换都正常 ## 相关文件 - `entry/src/main/ets/common/service/UnifiedPlayerService.ets`