Calling notifyListeners
Part of the State Management section of Coddy's Flutter journey. Lesson 10 of 27.
A ChangeNotifier keeps a list of listeners: every widget that called context.watch on it. Changing a field tells none of them. The model has to say it out loud:
void homeScores() {
_home++;
notifyListeners();
}notifyListeners() tells each listener "I changed", and Flutter builds those widgets again with the new values. It is what setState was for a State, but for a model that many widgets share.
Call it at the end of every method that changes the data. A method that forgets it still changes the field, but the screen keeps showing the old value until something else happens to rebuild it.
That is also why the fields are private: when the only way to change _home is a method, no change can sneak past notifyListeners.
Challenge
EasyThe buttons call the model's methods, and the scores do change inside it, but the screen stays at 0 : 0.
- Make
homeScores,awayScoresandreseteach tell their listeners after the change.
Try it yourself
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
class Scoreboard extends ChangeNotifier {
int _home = 0;
int _away = 0;
int get home => _home;
int get away => _away;
void homeScores() {
_home++;
}
void awayScores() {
_away++;
}
void reset() {
_home = 0;
_away = 0;
}
}
void main() {
runApp(
ChangeNotifierProvider(
create: (context) => Scoreboard(),
child: const MyApp(),
),
);
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return const MaterialApp(
debugShowCheckedModeBanner: false,
home: HomePage(),
);
}
}
class HomePage extends StatelessWidget {
const HomePage({super.key});
@override
Widget build(BuildContext context) {
final board = context.watch<Scoreboard>();
return Scaffold(
appBar: AppBar(title: const Text('Match')),
body: Center(
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
Text('${board.home} : ${board.away}', style: const TextStyle(fontSize: 48)),
const SizedBox(height: 16),
Row(
mainAxisSize: MainAxisSize.min,
children: [
ElevatedButton(
onPressed: () => context.read<Scoreboard>().homeScores(),
child: const Text('Home +1'),
),
const SizedBox(width: 16),
ElevatedButton(
onPressed: () => context.read<Scoreboard>().awayScores(),
child: const Text('Away +1'),
),
],
),
TextButton(
onPressed: () => context.read<Scoreboard>().reset(),
child: const Text('Reset'),
),
],
),
),
);
}
}
This lesson includes a short quiz. Start the lesson to answer it and track your progress.
All lessons in State Management
Practice on your own: Online Flutter compiler