播放上一首问题修复.md 4.0 KB

播放上一首问题修复

问题描述

用户点击"播放上一首"按钮时,虽然播放列表显示有上一首歌曲(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 中添加一个标志来标识当前是否正在进行手动歌曲切换:

private isManualSongChange: boolean = false; // 新增:是否正在进行手动歌曲切换

2. 在手动切换方法中设置标志

playNext()playPrevious()playSongAtIndex() 方法中:

async playPrevious(): Promise<void> {
  try {
    // 设置手动歌曲切换标志,防止自动播放干扰
    this.isManualSongChange = true;
    
    // ... 原有逻辑 ...
    
  } catch (error) {
    await this.handlePlaybackError(error as Error, PlayerErrorType.PLAYBACK_ERROR);
  } finally {
    // 确保在任何情况下都清除手动切换标志
    setTimeout(() => {
      this.isManualSongChange = false;
    }, 1000); // 延迟1秒清除,确保播放器状态稳定
  }
}

3. 在自动播放逻辑中检查标志

handleAutoPlayOnCompletion() 方法开头添加检查:

private async handleAutoPlayOnCompletion(): Promise<void> {
  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