Reputation: 5416
I'm trying to use Provider
with a Stateless
widget page to update a countdown UI.
When I run all the below, I get both print messages in the console on each 1 second tick of the stopwatch:
e.g.
flutter: build()
flutter: _buildCountDown()
Also, the remaining
value doesn't actually update in the UI.
But if I:
StatefulWidget
Consumer<CountdownProvider>
syntax e.g.return Consumer<CountdownProvider>(
builder: (_, countdownProvider, __) {
return Text(countdownProvider.remaining.toString()),
});
...everything works as expected: the UI updates properly and I don't get the build()
printout, just the _buildCountDown()
, which is what I wanted.
Q) What am I doing wrong that means I can't make this a Stateless widget that updates as expected?
return MultiProvider(
providers: [
ChangeNotifierProvider(
create: (_) => CountdownProvider(),
),
],
)
CountdownProvider
:class CountdownProvider extends ChangeNotifier {
int remaining = 0;
final Stopwatch _stopwatch = Stopwatch();
late Timer _timer;
void start(int val) {
remaining = val;
_timer = Timer.periodic(const Duration(seconds: 1), _onTick);
_stopwatch.start();
}
void _onTick(Timer timer) {
remaining--;
if (remaining < 0) {
return;
}
notifyListeners();
}
void stop(bool skipNotify) {
_timer.cancel();
_stopwatch.stop();
if (skipNotify) {
_stopwatch.reset();
remaining = 0;
return;
}
notifyListeners();
}
}
PageCountdown
:class PageCountdown extends StatelessWidget {
const PageCountdown({
Key? key,
}) : super(key: key);
@override
Widget build(BuildContext context) {
// 10 seconds default countdown
Provider.of<CountdownProvider>(context, listen: false).start(10);
print("build()");
return Scaffold(
body: _buildContent(context),
);
}
Widget _buildContent(BuildContext context) {
return SafeArea(
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
_buildCountDown(context),
],
),
);
}
Widget _buildCountDown(BuildContext context) {
int remaining = Provider.of<CountdownProvider>(context).remaining;
print("_buildCountDown()");
return Text(
remaining.toString(),
);
}
}
Upvotes: 2
Views: 779
Reputation: 8300
PageCountdown
is the single widget, which is rebuilt when the counter ticks. start(10)
in the beginning of build
will reset remaining
to 10 every rebuild. Something like this will work:
class PageCountdown extends StatelessWidget {
const PageCountdown({
Key? key,
}) : super(key: key);
@override
Widget build(BuildContext context) {
// 10 seconds default countdown
Provider.of<CountdownProvider>(context, listen: false).start(10);
print("build()");
return const Scaffold(
body: Countdown(),
);
}
}
class Countdown extends StatelessWidget {
const Countdown({
Key? key,
}) : super(key: key);
@override
Widget build(BuildContext context) {
return SafeArea(
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
_buildCountDown(context),
],
),
);
}
Widget _buildCountDown(BuildContext context) {
int remaining = Provider.of<CountdownProvider>(context).remaining;
print("_buildCountDown()");
return Text(
remaining.toString(),
);
}
}
Upvotes: 1