Menu
CoddyTech

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 icon

Challenge

Easy

The buttons call the model's methods, and the scores do change inside it, but the screen stays at 0 : 0.

  • Make homeScores, awayScores and reset each 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'),
            ),
          ],
        ),
      ),
    );
  }
}
quiz iconTest yourself

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