How to run a timer in initState flutter? - flutter

I've created an app using flutter and I want to get start a timer when the user navigates to a screen to calculate how long will he stay there.
I want if he has completed three minutes on the screen to print anything.
I don't have any ideas about the timer or how to use it.
please help me regarding achieving that.
thanks all.

You can do something like that.
Timer _timer;
#override
void initState() {
_timer = Timer(Duration(milliseconds: 500), () {
// SOMETHING
});
super.initState();
}
#override
void dispose() {
if (_timer != null) {
_timer.cancel();
_timer = null;
}
super.dispose();
}

Please have a look of this:
import 'dart:async';
main() {
const twentyMillis = const Duration(milliseconds:20);
new Timer(twentyMillis, () => print('hi!'));
}
Also look Timer class link

Related

How to add timer in tasks after being triggered in flutter

I am working on a slider in flutter which is focused on rating. I want to add a timer to manage a rating time (i.e if the user rated then he/she can't rate again for an hour. Which means once the function is triggered it won't trigger again for a specific time).
So how is it possible to do that. I have a little knowledge about the Timer class and I don't how exactly it should be done. By doing this we are bounding the user not to rate as many times as user want
A simple implementation using a Timer for the functionality you require is to store a bool and start the timer and toggle the bool value when the user performs the function and on timeout toggle the `bool to false and start the timer again.
Below is an example that uses setState.
import 'dart:async';
import 'package:flutter/material.dart';
void main() {
runApp(MaterialApp(home:TimerExample()));
}
class TimerExample extends StatefulWidget{
#override
State<StatefulWidget> createState() {
return _TimerExampleState();
}
}
class _TimerExampleState extends State<TimerExample> {
// Using a short timer for testing, set a duration
// you can set a any duration you like, For Example:
// Duration(hours: 1) | Duration(minutes: 30)
final _timeoutDuration = Duration(seconds:3);
late Timer _timer;
bool _canVote = true;
#override
void dispose() {
super.dispose();
_timer.cancel();
}
void onTimeout() {
setState(() => _canVote = true);
}
void startTimer() {
setState(() {
_canVote = false;
_timer = Timer(_timeoutDuration, onTimeout);
});
}
#override
Widget build(BuildContext context) {
return TextButton(
onPressed: _canVote ? startTimer : null,
child: Text('Vote')
);
}
}

dipsose() Being called at same time as initState()

I'm porting a offline Flutter game to online and the only difference in the code is that the new online code where the problem occurs has a active StreamSubscription being listened to. I can't find anything online other than 1 issue saying this is a bug.. any ideas on why dipose() is being called on the initial build?
class _OnlineSequenceState extends State<OnlineSequence> with SingleTickerProviderStateMixin {
//variable initialization would be here
#override
void initState(){
super.initState();
//setup gameRef
gameRef = FirebaseDatabase.instance.reference().child('sequence').child(widget.gameID);
//glow animation init
_setupGlowAnimtation();
//init sounds
_initSounds();
//setup player and card objects and create a stream
_setupGame();
}
#override
void dispose(){
print('disposing'); //prints on the widget being built for the first time
gameDataStream.cancel();
_animation.removeListener(() {});
_animationController.stop();
pool.dispose();
super.dispose();
}
_setupGlowAnimtation() {
_animationController = AnimationController(vsync: this, duration: Duration(milliseconds: 1300));
_animationController.repeat(reverse: true);
_animation = Tween(begin: 1.0, end: 6.4).animate(_animationController)
..addListener(() {
setState(() {});
});
}
_initSounds() async {
drawSound = await pool.load(await rootBundle.load('lib/assets/sounds/draw.wav'));
playCardSound = await (pool.load(await rootBundle.load('lib/assets/sounds/playcard.wav')));
shuffleSound = await (pool.load(await rootBundle.load('lib/assets/sounds/shuffle.wav')));
pool.play(shuffleSound);
}
...
The error turned out to actually be in the prior lobby screen. The host of the game would navigate to in-game screen twice instead of once causing weird dispose() behavior. Once I fixed the double navigation the issue went away.

Periodic Timer can not dispose

Code content is not important. Just one problem timer can not dispose when I want to leave this page. When I leave from this page, sendMessage("message"); function continue to run. Is there any option to dispose this timer?
Timer timer;
#override
void initState() {
super.initState();
timer = Timer.periodic(new Duration(seconds: 5), (timer) async {
setState(() {
unicode++;
unicodeString = unicode.toString();
if (unicodeString.length < 6) {
int different = 6 - unicodeString.length;
for (var i = 0; i < different; i++) {
unicodeString = "0" + unicodeString;
}
}
sendMessage("meesage");
showSnackBarWithKey("Message Sended !");
});
});
}
#override
void dispose() {
timer.cancel();
super.dispose();
}
The error is below.
EXCEPTION CAUGHT BY WIDGETS LIBRARY
The following assertion was thrown while finalizing the widget tree:
'package:flutter/src/widgets/framework.dart': Failed assertion: line 4182 pos 12:
'_debugLifecycleState != _ElementLifecycle.defunct': is not true.
Either the assertion indicates an error in the framework itself, or we should provide substantially
more information in this error message to help you determine and fix the underlying cause.
In either case, please report this assertion by filing a bug on GitHub:
I use dispose timer, but it can not dispose timer. I could not solve this problem. Help, please.
i findout issue after run your code,
the main problem is,
dispose is called on a widget when it is completely removed from the parent tree.
so when you route new page,
Using push navigation, a new screen is added on top of current
screen. hence the tree (of old screen) is not completely destroyed
hence dispose is not called.
using pop. the screen is removed so is the tree. hence dispose is
called.
using push replacement. new screen replaces old screen deleting the
widget tree. so dispose is called.
and for code,
try this.
(main part is pushReplacement i am using this for navigation)
Navigator.pushReplacement(
context, MaterialPageRoute(builder: (context) => SplashScreen()));
final code is,
class TimerButton extends StatefulWidget {
#override
_TimerButtonState createState() => _TimerButtonState();
}
class _TimerButtonState extends State<TimerButton> {
Timer _timer;
#override
void initState() {
super.initState();
_timer = Timer.periodic(new Duration(seconds: 5), (timer) async{
setState(() {
/* unicode++;
unicodeString = unicode.toString();
if (unicodeString.length < 6) {
int different = 6 - unicodeString.length;
for (var i = 0; i < different; i++) {
unicodeString = "0" + unicodeString;
}
}*/
sendMessage("meesage");
showSnackBarWithKey("Message Sended !");
});
});
}
#override
void dispose() {
_timer.cancel();
super.dispose();
}
#override
Widget build(BuildContext context) {
// TODO: implement build
return RaisedButton(
onPressed: (){
Navigator.pushReplacement(
context, MaterialPageRoute(builder: (context) => SplashScreen()));
},
child: Text("data"),
);
}
}
I hope the above solution works fine for you but if not, then you can also try the below code because in my case the above solution does not works fine.
static Timer timerObjVar;
static Timer timerObj;
timerObj = Timer.periodic(Duration(seconds: 10), (Timer timer) async {
timerObjVar = timer;
_initData();
});
// when you want to cancel the timer call this function
cancelTimer() {
if (timerObjVar != null) {
timerObjVar.cancel();
timerObjVar = null;
}
if (timerObj != null) {
timerObj.cancel();
timerObj = null;
}
}
Instead of dispose() try putting it in a deactivate().

Need Help updating chart data in flutter at every x amount of seconds

So I'm using the Sparkline library for flutter to create a line chart and it works when I use a static list Eg. ([0, 10, 20, 20, 30]). But I want to make it so that at every say 10 seconds it would add a value, for now that could be anything but later i want to pull that value from firebase.
I've looked at other examples of people trying to run a function multiple time init state but it isnt working. I know I need to redraw the widget but I don't think I'm doing it right or I'm missing something.
class BikeState extends State<BikeScreen> {
Timer timer;
List<double> speedList = new List();
Sparkline speedChart1 = Sparkline(data: [0],);
void updateChart(Timer timer){
speedChart1 = Sparkline(data: speedList,);
speedList.add(10);
speedChart1 = Sparkline(data: speedList,);
}
#override
void initState() {
super.initState();
timer = Timer.periodic(Duration(seconds: 15), updateChart);
}
#override
void dispose() {
timer?.cancel();
super.dispose();
}
All that happens when i run it is that I get the just the graph which has the values passed into it when it was declared and nothing was changed.
Flutter will not repaint or rebuild any widgets for you on its own. In your case you already have a stateful widget, which is the correct way, but you also need to tell flutter that your state has changed. This is done by using the setState method like this:
void updateChart(Timer timer) {
setState(() {
speedChart1 = Sparkline(data: speedList,);
speedList.add(10);
speedChart1 = Sparkline(data: speedList,);
});
}
Additionally, depending on how your build method looks, I think you should remove the Sparkline Widget from your state and have it purely during build like this:
class BikeState extends State<BikeScreen> {
Timer timer;
List<double> speedList = new List();
void updateChart(Timer timer){
setState(() {
speedList.add(10);
});
}
#override
void initState() {
super.initState();
timer = Timer.periodic(Duration(seconds: 15), updateChart);
}
#override
void dipose() {
timer?.dipose();
super.dispose();
}
#override
Widget build(BuildContext context) {
return Sparkline(data: speedList);
}
}

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!
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.