#问题现象
在开发Flutter视频播放器时,遇到了一个非常有意思的现象:
- 当前播放第3个片段,向后跳到6等不正常,会先跳到片段6,然后再跳到4 这个现象非常奇怪?
#问题代码
// 用户手动切换片段
void _switchToSegment(int index) {
// 切换视频,设置新的播放位置
await _processSegmentBoundaries(newSegment);
_controller!.play();
}
// 视频播放监听器
void _videoListener() {
// 检测是否播放到片段结尾
if (currentPosition >= adjustedEndTime) {
_handleNextSegment(); // 这里又会调用 _switchToSegment
}
}#调试发现的问题
当调用 _switchToSegment(index) 时:
- 向后跳(如3→6):
- 调用
_switchToSegment(6) - 视频跳转到第6个片段的开始位置
_videoListener检测当前播放位置,发现已经大于原片段的 adjustedEndTime- 那么则调用_handleNextSegment方法, 跳转到3的下一个片段4
- 调用
核心问题:_videoListener 在 _switchToSegment 还没完全初始化完成时就开始工作了。
#解决思路
问题的本质是竞态条件:用户手动切换和自动切换逻辑产生了冲突。 解决思路很简单:加一个标志位,让这两个操作互相隔离。
#解决方案
class VideoPlayerState extends State<VideoPlayer> {
// 添加标志位
bool _isSwitchingSegment = false;
void _videoListener() {
// 如果正在手动切换片段,忽略自动切换逻辑
if (_isSwitchingSegment) {
return;
}
// 原有的自动切换逻辑
if (currentPosition >= adjustedEndTime) {
_handleNextSegment();
}
}
Future<void> _switchToSegment(int index) async {
// 设置标志位
_isSwitchingSegment = true;
try {
// 执行切换逻辑
await _processSegmentBoundaries(newSegment);
setState(() {
_currentSegmentIndex = index;
_isPlaying = true;
});
_controller!.play();
} finally {
// 无论成功失败,都要重置标志位
_isSwitchingSegment = false;
}
}
}#总结
这个bug很好地展示了异步编程中的经典问题:竞态条件。
- 现象:看似简单的功能,却出现了方向性的差异
- 本质:两个异步操作之间的时序冲突
- 解决:通过状态标志位进行操作隔离 这提醒我们在处理用户交互和自动逻辑并存的场景时,一定要考虑它们之间的相互影响,必要时需要加入状态管理来避免冲突。
有问题请留言~
在 GitHub 查看讨论