I was facing this annoying issue in Flutter music player:
When you tap songs quickly (like switching from one to another), playback breaks, mini player disappears, and you have to tap again to play. It was 2-3 times out of every 10 switch.
It took me a while to trace it. I tried:
- Making our playback function async
- Adding delays
- Debugging tap triggers
But nothing worked.
Then I found the real culprit:
await _player.stop(); // this innocent-looking line was breaking everything
The Wrong Code
In the background audio handler's updateQueue() method:
Future<void> updateQueue(List<MediaItem> newQueue) async {
final newAudioSources = newQueue.map((item) {
final uri = item.extras?['uri'] as String;
return AudioSource.uri(Uri.parse(uri));
}).toList();
await _player.setAudioSource(_playlist, initialIndex: 0);
await _player.stop(); // ❌ this line breaks playback!
queue.add(newQueue);
}
What’s the Problem?
This creates a race condition:
- setAudioSource() loads and prepares the new song(s).
- Immediately after, stop() wipes the loaded source.
- So by the time the player is supposed to play, there's nothing left
to play.
This bug especially shows up during rapid song switching, because set -> stop -> play happens too fast and gets out of sync.
The Right Code
Future<void> updateQueue(List<MediaItem> newQueue) async {
final newAudioSources = newQueue.map((item) {
final uri = item.extras?['uri'] as String;
return AudioSource.uri(Uri.parse(uri));
}).toList();
_playlist.clear();
_playlist.addAll(newAudioSources);
await _player.setAudioSource(_playlist, initialIndex: 0);
if (_player.playing) {
await _player.play();
}
queue.add(newQueue);
}
If you're using just_audio and audio_service, never call stop() right after setAudioSource().
You're basically loading a song and immediately throwing it away.
Let the player handle resets internally unless you truly need to stop everything.
Happy building!