I recently ran into a subtle but super frustrating issue in my Flutter music player app using just_audio and audio_service. It had to do with updating the playback queue when selecting a new song — and I want to share how I fixed it.
The Problem
Let’s say I have 5 songs:
a b c d e
Here's what was happening:
I open the app and click on song b.
Music starts playing . I can see the notification with controls.
I click next in the notification → it moves to c. Perfect!
I go back to the app and tap on song a.
Now... song plays but playback control like next and previous don't work.
So clearly, something went wrong when I tried to load a new playlist and song from the UI.
My (Buggy) Code
This is how I was updating the queue in my AudioHandler:
Future<void> updateQueue(List<MediaItem> newQueue) async {
await _player.stop(); // Stop current audio
_playlist.clear(); // Clear existing playlist
final audioSources = newQueue.map((item) {
final uri = item.extras?['uri'] as String;
return AudioSource.uri(Uri.parse(uri));
}).toList();
_playlist.addAll(audioSources); // Add new items to old list
await _player.setAudioSource(_playlist); // Reuse the same playlist
queue.add(newQueue); // Update the queue
}
The Hidden Issue
I was clearing and modifying the same _playlist instance that was already connected to the player.
just_audio doesn't always like it when you mutate a ConcatenatingAudioSource after it's been set — especially if it's already active in playback.
That caused inconsistent behavior.
The Fix: Use a Fresh Playlist Instance
Instead of modifying the existing _playlist, I now create a brand new ConcatenatingAudioSource every time I update the queue:
@override
Future<void> updateQueue(List<MediaItem> newQueue) async {
await _player.stop(); // Stop safely
final newAudioSources = newQueue.map((item) {
final uri = item.extras?['uri'] as String;
return AudioSource.uri(Uri.parse(uri));
}).toList();
final newPlaylist = ConcatenatingAudioSource(children: newAudioSources); // Fresh playlist
await _player.setAudioSource(newPlaylist); // Clean set
_playlist.clear(); // Optional: if you track items
_playlist.addAll(newAudioSources);
queue.add(newQueue); // Update queue after setting source
}
When working with just_audio and audio_service, always pass a new AudioSource instance when switching playlists or queues.
Avoid mutating an existing one after it’s been assigned to the player. Otherwise, you'll run into strange bugs like:
Next/Previous buttons breaking
Playback getting stuck
Notifications going out of sync