I'm working on making a music playing app in Flutter and the current code I've got only works properly after hot restarting. In particular, after pressing play or as soon as I release the slider, the currentTime of the song gets reset back to zero. However, as soon as I hot restart the app, everything works perfectly as intended.
As I eventually hope to use this app on an iOS device, which does not have hot restart, this is a major issue.
I'm using audioplayers 0.20.1 as right now 4.1.0 isn't recognizing my mp3 files (another issue)
If the code below doesn't run it's because I removed some of the styling widgets to make it more readable but hopefully you can see all the relevant parts.
import 'package:pick_pro/main.dart';
import 'package:audioplayers/audioplayers.dart';
class Playback extends StatefulWidget {
@override
PlaybackState createState() => PlaybackState();
}
class PlaybackState extends State<Playback> {
final player = AudioPlayer();
late Duration songLength;
late Duration currentTime;
double playbackSpeed = 1;
String assetPath = 'assets/sounds/demo_song.mp3';
bool isPlaying = false;
int bpm = 100;
@override
void initState() {
super.initState();
player.setReleaseMode(ReleaseMode.STOP);
player.setUrl(assetPath, isLocal: true);
currentTime = Duration.zero;
songLength = const Duration(seconds: 259);
// Listeners for changes in player states
player.onPlayerStateChanged.listen((state) {
setState(() {
isPlaying = state == PlayerState.PLAYING;
});
});
player.onDurationChanged.listen((newSongLength) {
setState(() {
songLength = newSongLength;
});
});
player.onAudioPositionChanged.listen((newCurrentTime) {
setState(() {
currentTime = newCurrentTime;
});
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: Container(
color: darkBlue,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Slider(
min: 0,
max: songLength.inSeconds.toDouble(),
value: currentTime.inSeconds.toDouble(),
onChanged: (value) {
final position = Duration(seconds: value.toInt());
player.pause();
player.seek(position);
setState(() {});
}),
const SizedBox(height: 20),
IconButton(
icon: Icon(isPlaying ? Icons.pause : Icons.play_arrow,
color: Colors.white),
iconSize: 50,
onPressed: () {
if (isPlaying) {
player.pause();
} else {
player.seek(currentTime);
player.resume();
}
},
),
const SizedBox(height: 20),
Slider(
min: 0.5,
max: 1.5,
value: playbackSpeed,
onChanged: (value) {
playbackSpeed = double.parse(value.toStringAsFixed(2));
player.pause();
player.setPlaybackRate(playbackSpeed);
setState(() {});
}),
Center(
child: Text(
'Speed: ${playbackSpeed}x',
style: buttonText(),
),
),
const SizedBox(
height: 30,
),
Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.start,
children: [
SizedBox(
width: 60.0,
height: 30.0,
child: TextField(
onSubmitted: (String value) {
_controller.clear();
try {
bpm = int.parse(value);
setState(() {});
} catch (e) {
ErrorPopup.show(
context, "The BPM you entered is invalid.");
}
},
),
),
],
),
Row(
mainAxisAlignment: MainAxisAlignment.start,
children: [
SizedBox(
width: 60.0,
height: 30.0,
child: TextField(
onSubmitted: (String value) {
_controller.clear();
try {
int newBPM = int.parse(value);
playbackSpeed =
double.parse((newBPM / bpm).toStringAsFixed(2));
player.pause();
player.setPlaybackRate(playbackSpeed);
setState(() {});
} catch (e) {
ErrorPopup.show(
context, "The BPM you entered is invalid.");
}
},
),
),
],
),
],
),
],
),
),
drawer: MyDrawer(index: 3),
);
}
}
I don't know what to try with this, as it works perfectly after hot restarting. I just don't know how hot restart works so I don't know why the code works after a hot restart but not before.