I am having a problem with cancelling one nested Timer. These are the code example I have:
import 'dart:async';
void main() async{
final timer =
Timer(const Duration(seconds: 1), () {
print('Timer 1');
Timer(const Duration(seconds:1),(){
print('Timer 2');
});
});
Timer(Duration(milliseconds: 1500),(){
timer.cancel();
print('timer cancelled');
});
}
The result:
Timer 1
timer cancelled
Timer 2
What I am expected:
Timer 1
timer cancelled
A little about my usecase, I want to create a quite complex animation and I use the nested Timer to set the specific timing of the animation.
The problem occur when the user move forward and instantinously move backward, the animation that still inside the Timer will still run 'forward' (because it's still deep inside the nested timer) even though the 'reverse' animation should be the only one that run.
That is why I am only expecting Timer 1 to be printed instead of both Timer 1 and 2 even though the Timer has been cancelled
Any feedback or input would be appreciated.
What I am expected:
Timer 1
timer cancelled
I think this will print your expected result. Just keep a reference to the second Timer. You can reuse the existing timer variable since after the first Timer fires to create the second Timer, you no longer need a reference to the first one.
import 'dart:async';
void main(List<String> args) {
Timer? timer = null;
timer = Timer(const Duration(seconds: 1), () {
print('Timer 1');
timer = Timer(const Duration(seconds: 1),(){
print('Timer 2');
});
});
Timer(Duration(milliseconds: 1500),(){
timer?.cancel();
print('timer cancelled');
});
}
Related
Problem
I'm doing a chat. I want the program to try to get messages again every 5 seconds if there are no messages.
My solution
I'have created a Timer in my stateful widget.
Timer timer;
When I build a widget, I check for messages. If there are none, I start the timer. I want the timer to stop at the next check, in case of existing messages
void onBuild() {
if (state.messages.isEmpty) {
_checkEmptyMessages();
timer = Timer.periodic(
Duration(seconds: 5), (Timer t) => _checkEmptyMessages());
}
}
void _checkEmptyMessages() {
print('MES789 ${state.messages.isEmpty}');
if (state.messages.isEmpty) {
add(ChatEventLoadFirstPage()); // This adds an event to the BLoC
} else {
if (timer != null) timer.cancel();
timer = null;
}
}
Also I've tried
I've tried to remove timer = null; and await for timer.cancel();, but it didn't help.
Actual output
So in the Debug Console I get this every 5 seconds:
I/flutter (13387): MES789 false
I/flutter (13387): MES789 false
I/flutter (13387): MES789 false
I/flutter (13387): MES789 false
Question
How can I stop the Timer?
Because 'Timer.periodic' is called, new Timer instance is created and stored same timer variable.
It means that not canceled timer's instance will be lost when 'Timer.periodic' is called.
So you need to check whether Timer instance is exist.
void onBuild() {
if (state.messages.isEmpty) {
if (timer == null) {
timer = Timer.periodic(
Duration(seconds: 5), (Timer t) => add(ChatEventLoadFirstPage()));
}
} else {
if (timer != null) timer.cancel();
timer = null;
}
}
this code is dead code, it will never work because you have if (state.messages.isEmpty) before _checkEmptyMessages() and if (state.messages.isEmpty) again, try to remove first if (state.messages.isEmpty)
I am new to flutter and I have a problem with a flutter function. It adds data to graph and I programmed a button to start updating the graph. How do I stop it? I created another button and I want to program it to stop the function that adds the graph.
The function:
void updateDataSource(Timer timer) {
chartData.add(LiveData(time++, (y)));
chartData.removeAt(0);
_chartSeriesController.updateDataSource(
addedDataIndex: chartData.length - 1, removedDataIndex: 0);
}
The first button:
onPressed: () {
Timer.periodic(const Duration(seconds: 1), updateDataSource);
},
The second button:
onPressed: () {
chartData.clear();
},
I put chartData.clear() but that clears everything and I am unable to call back the function again.
Thanks in advance!
This is due to your Timer.periodic function which is running every second
Solution:
Create a state timer variable
Timer? _timer;
Assign a value to the timer when you first onPressed
onPressed: (){
_timer = Timer.periodic(const Duration(seconds: 1), updateDataSource);
setState((){});
},
And when you want to stop adding graphs Do.
onPressed: () {
if(_timer !=null) {
_timer.cancel();
}
},
This is common in other languages. setTimeout(fn, 0) in JavaScript, and DispatchQueue.main.async() {} in Swift.
How best to do this in Flutter?
I have used Future.delayed(Duration.zero).then(fn), but I don't like it because like JS's setTimeout and unlike swifts DispatchQueue.main.async() {} it doesn't really express the intent, only the behaviour. Is there a way of doing this that is the correct way to do this in Flutter.
Use addPostFrameCallback
WidgetsBinding.instance
.addPostFrameCallback((timestamp) {
print("I'm running after the frame was built");
});
This will cause your callback function to run right after flutter has finished building the current frame.
Note that the callback will only run once, if you want to reschedule it for each build, set the callback at the beginning of the build function.
#override
Widget build(BuildContext context) {
WidgetsBinding.instance
.addPostFrameCallback((timestamp) {
print("I'm running after the frame was built");
});
return Container();
}
You can also use Timer from flutter.
Example
Timer(Duration(seconds: 1), () {
print('hai');
});
Duration gives you options with seconds,milliseconds,days,hours,minutes.
You can achieve setInterval also using Timer
Timer.periodic(Duration(seconds: 1), (Timer timer) {
print('hai');
});
But keep in mind that to cancel the timer on dispose.This would save you from hitting memory
Timer timer;
timer = Timer(Duration(seconds: 1), () {
print('hai');
});
void dispose() {
timer.cancel();
}
Is it possible to recall a function every x seconds at flutter? And notify if there are changes?
the code is as follows
List<Any> any =
await Api.getAny(++widget.appState.lastPage, widget.datauser);
widget.appState.issues.addAll(issues);
setState(() {});
}```
Actually It is easy to run function every x amount of seconds on flatter.
You can use Timer to recall function per x seconds.
Timer timer;
void initState() {
super.initState();
timer = Timer.periodic(Duration(seconds: 15), (Timer t) => checkForNewSharedLists());
}
void dispose() {
timer.cancel();
super.dispose();
}
In some area, I want a list of objects to be continuously appeared replacing the previous one in a gap of 2 secs. And in that interval I wanna do some logic.
I tried Flutter.delayed but it doesn't work accordingly in a while loop.
In your initState method, use Timer.periodic(...)
#override
void initState() {
super.initState();
// this code runs after every 2 seconds.
Timer.periodic(Duration(seconds: 2), (timer) {
if (_someCondition) {
timer.cancel(); // if you want to stop this loop use cancel
}
setState(() {
_string = "new value"; // your logic here
});
});
}
Create a timer and put your logic in the function that handles the timer event.
...
...
initstate() {
Timer.periodic( Duration(seconds: 2), (Timer t) {
setState(() => displayTheNextElementOfTheList());
...
//your logic here
});
...
}