

在 Flutter 开发中,状态管理(State Management) 是构建可维护、可扩展应用的核心技能之一。本文将通过一个简洁但完整的“计数器”示例,深入讲解如何使用官方推荐的状态管理方案 —— Provider,实现数据驱动 UI 更新。
Provider 是 Flutter 团队推荐的轻量级状态管理工具,具有以下优势:
InheritedWidget 封装,性能优秀整个应用包含四个核心部分:
下面我们逐段解析。
CounterModelclass CounterModel with ChangeNotifier {
int _count = 0;
int get count => _count;
void increment() {
_count++;
notifyListeners();
}
void reset() {
_count = 0;
notifyListeners();
}
}with ChangeNotifier
使该类具备通知能力。当调用 notifyListeners() 时,所有监听此对象的 Widget 会自动重建。
_count + 公共 getter
封装数据,防止外部直接修改,确保状态只能通过方法变更(符合状态管理最佳实践)。
notifyListeners()
触发 UI 更新的关键。每次状态改变后必须调用,否则界面不会刷新。
⚠️ 注意:不要在
build方法中直接调用notifyListeners(),否则会导致无限循环!
void main() {
runApp(
ChangeNotifierProvider(
create: (context) => CounterModel(),
child: const MyApp(),
),
);
}ChangeNotifierProvider
是 Provider 提供的专门用于包裹 ChangeNotifier 子类的 Provider。
create 回调
在此处创建 CounterModel 实例,并将其“注入”到 Widget 树中。整个 App 的子组件都可以通过 Provider.of 或 Consumer 访问它。
MyApp 外层,CounterModel 对整个应用可见。
MyAppclass MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Provider 状态管理测试',
theme: ThemeData(primarySwatch: Colors.blue),
home: const CounterScreen(),
);
}
}这是一个标准的 Flutter 应用壳,无特殊逻辑,仅用于启动 CounterScreen 页面。
CounterScreenclass CounterScreen extends StatelessWidget {
const CounterScreen({super.key});
@override
Widget build(BuildContext context) {
final counter = Provider.of<CounterModel>(context);
return Scaffold(
appBar: AppBar(title: const Text('VON - 状态管理测试')),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
const Text('当前计数:', style: TextStyle(fontSize: 18)),
Consumer<CounterModel>(
builder: (context, model, child) {
return Text('${model.count}', style: TextStyle(fontSize: 48));
},
),
ElevatedButton(onPressed: counter.increment, child: Text('➕ 增加')),
ElevatedButton(onPressed: counter.reset, child: Text('↺ 重置')),
],
),
),
);
}
}Provider.offinal counter = Provider.of<CounterModel>(context);CounterModel 实例。Provider.of 会监听变化(即当 notifyListeners() 被调用时,当前 Widget 会 rebuild)。🔍 如果你只想读取一次而不监听,可传入
listen: false:Provider.of<CounterModel>(context, listen: false)
ConsumerConsumer<CounterModel>(
builder: (context, model, child) {
return Text('${model.count}');
},
)Consumer 是一种更精细的监听方式,只重建其内部的 builder 部分,而非整个 CounterScreen。💡 在本例中,其实两种方式效果相同。但若页面复杂,
Consumer更高效。
onPressed: counter.increment当你运行此应用:
00Provider 驱动,无需手动调用 setState


🌟 结语:状态管理不是炫技,而是为了写出更清晰、更可维护的代码。从
Provider入手,是你迈向 Flutter 高阶开发的重要一步。
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
// 1. 状态模型:继承 ChangeNotifier
class CounterModel with ChangeNotifier {
int _count = 0;
int get count => _count;
void increment() {
_count++;
notifyListeners(); // 通知所有监听者重建
}
void reset() {
_count = 0;
notifyListeners();
}
}
// 2. 主应用入口
void main() {
runApp(
// 将 CounterModel 提供给整个 App
ChangeNotifierProvider(
create: (context) => CounterModel(),
child: const MyApp(),
),
);
}
// 3. 主界面
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Provider 状态管理测试',
theme: ThemeData(primarySwatch: Colors.blue),
home: const CounterScreen(),
);
}
}
// 4. 计数器页面
class CounterScreen extends StatelessWidget {
const CounterScreen({super.key});
@override
Widget build(BuildContext context) {
// 通过 Provider 读取状态
final counter = Provider.of<CounterModel>(context);
return Scaffold(
appBar: AppBar(title: const Text('VON - 状态管理测试')),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
const Text(
'当前计数:',
style: TextStyle(fontSize: 18),
),
// 使用 Consumer 自动监听变化(也可用 Selector 优化)
Consumer<CounterModel>(
builder: (context, model, child) {
return Text(
'${model.count}',
style: const TextStyle(fontSize: 48, fontWeight: FontWeight.bold),
);
},
),
const SizedBox(height: 30),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
ElevatedButton(
onPressed: counter.increment,
child: const Text('➕ 增加'),
),
const SizedBox(width: 20),
ElevatedButton(
onPressed: counter.reset,
child: const Text('↺ 重置'),
),
],
),
],
),
),
);
}
}