Reputation: 2462
I'm trying to execute a callback function once a timer ends in a particular widget but I keep getting this exception:
I/flutter (16413): Another exception was thrown: setState() or markNeedsBuild() called during build.
So I have this widget called countdown
:
class Countdown extends StatefulWidget {
final VoidCallback onCountdownExpire;
Countdown(this.onCountdownExpire);
@override
CountdownState createState() => CountdownState();
}
class CountdownState extends State<Countdown> with TickerProviderStateMixin {
AnimationController controller;
String get timerString {
Duration duration = controller.duration * controller.value;
return '${duration.inMinutes}:${(duration.inSeconds % 60).toString()}';
}
@override
void initState() {
super.initState();
controller = AnimationController(
vsync: this,
duration: Duration(seconds: 2),
)..addStatusListener((AnimationStatus status){
if (status == AnimationStatus.completed)
widget.onCountdownExpire();
});
controller.reverse(from: 1.0);
}
...
...
... // omitted code
}
So once the animation is completed it will call the callback function:
class _QuizPageState extends State<QuizPage> {
... // omitted code
@override
void initState() {
... // omitted code
}
void onCountdownExpire() {
setState(() {
_topContentImage = AssetImage(questions[questionNum++].imagePath);
});
}
... // omitted code
}
I've tried to follow a solution but it does not work and gives me the same exception:
void onCountdownExpire() =>
setState(() {
_topContentImage = AssetImage(questions[questionNum++].imagePath);
});
I also tried this but to no avail:
@override
void initState() {
super.initState();
controller = AnimationController(
vsync: this,
duration: Duration(seconds: 2),
)..addStatusListener((AnimationStatus status) =>
(status == AnimationStatus.completed) ?
widget.onCountdownExpire():null
);
controller.reverse(from: 1.0);
}
Upvotes: 0
Views: 917
Reputation: 1512
maybe try including 'dart:async':
import 'dart:async';
then try wrapping your call of the onCountdownExpire
function in a short-lived Timer()
:
...
Timer(
Duration(milliseconds:50),
() {
if (status == AnimationStatus.completed)
widget.onCountdownExpire();
},
);
...
this will make the setState()
happen outside the build phase of the last frame of your animation.
The error occurs most likely because the Countdown()
is being redrawn as part of the redraw of the QuizPage()
widget. Adding the Timer()
will force the update to happen outside of the build()
scope, in an async fashion, and will still achieve the same results without the error.
Upvotes: 2