Derence
Derence

Reputation: 428

Async/Await not working as expect. How can I start a timer exactly 4 seconds after a sound has started playing in Flutter?

When my app's game screen appears, an audio file starts playing that says "Ready? 3...2...1...GO" and then plays music.

I'd like the game timer to start at the same time that it says "GO", which is exactly 4 seconds into the audio.

I got pretty close by starting the audio file in initState() and then using "Future.delayed(const Duration(seconds: 4), () => startTimer());" but the problem is that the first time a user plays, it take a bit of time for the audio to load, so then the timer starts before the audio says "GO".

I tried to solve this by making an startGameSequence() function that uses async and await, but it isn't working. What am I doing wrong?

Here's what I've got so far:

import 'package:audioplayers/audio_cache.dart';
import 'dart:async';

class GameScreen extends StatefulWidget {
  @override
  _GameScreenState createState() => _GameScreenState();
}

class _GameScreenState extends State<GameScreen> {

  void loadAudio() {
    final player = AudioCache();
    player.load('audio/ready-321-go-music.mp3');
  }

  void playAudio() {
    final player = AudioCache();
    player.play('audio/ready-321-go-music.mp3');
  }

  void startGameSequence() async {
    await loadAudio(); 
    playAudio();

    // After audio finishes loading / starts playing, THEN I'd like the 4-second delayed timer to start. (Currently, it seems that the time starts too early because the audio takes a bit to load.)

    Future.delayed(
      const Duration(seconds: 4),
          () => startTimer(),
    );    
  }

  Timer _timer;
  double _timeRemaining = 7.00;

  void startTimer() {
    const tick = const Duration(milliseconds: 10);
    _timer = new Timer.periodic(
      tick,
          (Timer timer) => setState(
            () {
          if (_timeRemaining < 0.01) {
            timer.cancel();
          } else {
            _timeRemaining = _timeRemaining - 0.01;
          }
        },
      ),
    );
  }

  @override
  initState() {
    super.initState();
    startGameSequence();    
  }

Thank you in advance for any help!

Upvotes: 1

Views: 1141

Answers (1)

Eduardo Yamauchi
Eduardo Yamauchi

Reputation: 849

InitState is not async, wherefore this not working correctly.

A one solution is, load the audioFile in initState() and execute startGameSequence() in didUpdateWidget() function without the Future.delayed() .

@override
initState() {
  super.initState();
  await loadAudio();    
}

@override
void didUpdateWidget(GameScreen oldWidget) {
  startGameSequence()
  super.didUpdateWidget(oldWidget);
}

void startGameSequence() {
  playAudio();
}

This function execute just when the first layout appears on the screen.

Upvotes: 0

Related Questions