目录
在 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(); // 通知监听器执行更新操作
}
}
它的工作原理如下:
你调用 notifyListeners();
系统会遍历通过 addListener() 注册的所有监听器(回调函数);
执行每一个监听器的回调(例如 UI 中的 setState);
从而实现页面或逻辑的自动响应更新。
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函数中移除观察者,否则会有内存泄漏的风险。