Flutter状态管理篇之ChangeNotifier(一)

发布于:2025-07-18 ⋅ 阅读:(15) ⋅ 点赞:(0)

目录

一、什么是ChangeNotifier?

二、ChangeNotifier的常用API

1.addListener

2.removeListener方法

3.notifyListeners

4.removerListener

三、ChangeNotifier的用法

1.定义状态类

2.创建StatefulWidget

3.完整代码

四、参考文档


        在 Flutter 中,状态管理是构建动态应用的核心。而在众多状态管理方式中,ChangeNotifier 是最基础、最常见的实现方式之一。

        本文将从原生角度 出发,不依赖任何第三方库(如 Provider),通过真实案例,带你理解 ChangeNotifier 的工作原理与使用方式。

一、什么是ChangeNotifier?

        ChangeNotifier 是一个 Flutter SDK 中的类,位于 foundation 包中。它提供了一种简单的观察者模式:

        可以注册监听器(addListener());

        当状态改变时调用 notifyListeners(),通知所有监听器更新状态。

它是 Flutter 原生支持的响应式状态模型,非常轻量,适合中小项目或局部状态管理。

二、ChangeNotifier的常用API

1.addListener

        ChangeNotifier 实现了“观察者模式”,允许其他对象“监听”它。当它的状态改变时(例如你调用了 notifyListeners()),它就会通知所有添加的监听器,让它们执行对应的逻辑,比如刷新 UI。

2.removeListener方法

        当页面销毁的时候,我们记得调用removeListener方法防止内存泄漏。

3.notifyListeners

        notifyListeners() 是 ChangeNotifier 类中的一个方法,用于通知所有通过 addListener() 注册的监听器:数据发生了变化。

        在下面的代码中:

class Counter extends ChangeNotifier {
  int _count = 0;

  int get count => _count;

  void increment() {
    _count++;            // 状态发生变化
    notifyListeners();   // 通知监听器执行更新操作
  }
}

        它的工作原理如下: 

  1. 你调用 notifyListeners();

  2. 系统会遍历通过 addListener() 注册的所有监听器(回调函数);

  3. 执行每一个监听器的回调(例如 UI 中的 setState);

  4. 从而实现页面或逻辑的自动响应更新。

4.removerListener

        当你不再需要监听时,一定要调用 removeListener(),否则会内存泄漏。

三、ChangeNotifier的用法

        我们以下面的UI为例:

1.定义状态类

        首先我们定义一个继承自ChangeNotifier的类。

import 'package:flutter/foundation.dart';

class Counter extends ChangeNotifier {
  int _count = 0;

  int get count => _count;

  void increment() {
    _count++;
    notifyListeners(); // 通知监听器状态发生变化
  }
}

2.创建StatefulWidget

        我们将状态保存在 State 中,并手动监听它的变化。

class MyHomePage extends StatefulWidget {
  const MyHomePage({super.key, required this.title});
  final String title;

  @override
  State<MyHomePage> createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  final Counter _counter = Counter(); // 创建状态对象
  @override
  void initState() {
    super.initState();
    _counter.addListener(_onCounterChange);//添加监听器
  }
  void _onCounterChange(){
    setState(() {

    });
  }
  @override
  void dispose() {
    super.dispose();
    _counter.removeListener(_onCounterChange);
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        backgroundColor: Theme.of(context).colorScheme.inversePrimary,
        title: Text(widget.title),
      ),
      body: Column(
        mainAxisAlignment: MainAxisAlignment.center,
        children: [
          Text(
            '当前用户点击次数',
            style: const TextStyle(fontSize: 12),
          ),
          Container(height: 20,),
          Text(
            '${_counter.count}',
            style: const TextStyle(fontSize: 20,fontWeight:FontWeight.bold ),
          )
        ],
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: _counter.increment,
        tooltip: 'Increment',
        child: const Icon(Icons.add),
      ), // This trailing comma makes auto-formatting nicer for build methods.
    );
  }
}

3.完整代码

        完整的代码如下:

import 'package:flutter/material.dart';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
      ),
      home: const MyHomePage(title: 'Flutter ChangeNotifier用法'),
    );
  }
}

class MyHomePage extends StatefulWidget {
  const MyHomePage({super.key, required this.title});
  final String title;

  @override
  State<MyHomePage> createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  final Counter _counter = Counter(); // 创建状态对象
  @override
  void initState() {
    super.initState();
    _counter.addListener(_onCounterChange);//添加监听器
  }
  void _onCounterChange(){
    setState(() {

    });
  }
  @override
  void dispose() {
    super.dispose();
    _counter.removeListener(_onCounterChange);
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        backgroundColor: Theme.of(context).colorScheme.inversePrimary,
        title: Text(widget.title),
      ),
      body: Column(
        mainAxisAlignment: MainAxisAlignment.center,
        children: [
          Text(
            '当前用户点击次数',
            style: const TextStyle(fontSize: 12),
          ),
          Container(height: 20,),
          Text(
            '${_counter.count}',
            style: const TextStyle(fontSize: 20,fontWeight:FontWeight.bold ),
          )
        ],
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: _counter.increment,
        tooltip: 'Increment',
        child: const Icon(Icons.add),
      ), // This trailing comma makes auto-formatting nicer for build methods.
    );
  }
}

class Counter extends ChangeNotifier{
  int _count = 0;
  int get count => _count;
  void increment() {
      _count++;
      notifyListeners(); // 通知监听器状态发生变化
  }
}

        这里要注意的是我们忘记了在dispose函数中移除观察者,否则会有内存泄漏的风险。

四、参考文档


网站公告

今日签到

点亮在社区的每一天
去签到