Flutter状态管理那些事儿:一个国企程序员的避坑指南
上周五下班前,产品经理又在群里@我:“这个页面的状态逻辑能不能再优化一下?用户反馈切换 tab 有点卡。” 我看了眼时间——17:58,离打卡只剩两分钟。心里默默翻了个白眼,但还是回了个“好的,下个版本优化”。毕竟,在我们这种双休不加班(真的不加!)的国企,大家讲究的是“情绪稳定、按时下班、代码整洁”。
我是谁?一个混迹某省属信息集团三年的Flutter开发,VSCode插件装了快50个,最近一边刷LeetCode准备跳槽,一边被安排重构公司主力App的状态管理模块。说白了,就是领导看老项目用setState写得跟意大利面条一样,怕哪天线上崩了背锅,让我“优雅地重构一下”。
于是,就有了这篇技术分享。不为别的,就当给未来的面试官看看:我不仅会写业务逻辑,还能把状态管得明明白白。
事情是怎么开始的?
去年双11期间,我们App搞了个促销活动页。前端用Flutter快速搭了个界面,后端配合上了个简单的爬虫服务(对,你没看错,国企也搞爬虫,只是用来抓公开招标数据而已,合规得很)。结果上线第三天,测试小姐姐跑来跟我说:“用户切换筛选条件时,页面偶尔会闪回默认状态,而且内存占用飙到400MB!”
我打开DevTools一看——好家伙,每个筛选项都绑着setState,一改就全页面重建。更离谱的是,有些FutureBuilder嵌套三层,数据一变就触发多次网络请求。当时真的想砸电脑。
问题根源很明确:状态管理太随意。没人规定用什么方案,有人用Provider,有人直接setState,还有人硬生生用GlobalKey传状态……代码像拼夕夕缝合怪。
选型:别整花活,稳字当头
作为准备跳槽的人,我深知面试官最爱问“你们项目用什么状态管理?为什么选它?” 所以这次重构,我得选个业界主流 + 文档完善 + 团队能快速上手的方案。
对比了几个主流方案:
| 方案 | 学习成本 | 调试体验 | 适合场景 | 国企适配度 |
|---|---|---|---|---|
| setState | 极低 | 差(无追踪) | 超简单UI | ⭐(但别滥用) |
| Provider | 中 | 良好 | 中小型项目 | ⭐⭐⭐⭐ |
| Riverpod | 中高 | 优秀 | 中大型 | ⭐⭐⭐ |
| Bloc/Cubit | 高 | 极佳 | 复杂状态流 | ⭐⭐(团队抗拒写样板代码) |
最后我拍板:Provider + 少量Riverpod混合使用。理由很简单:
- 团队里新人多,Bloc那套event/state转换太重;
- Provider是官方推荐,生态成熟,连pub.dev下载量都碾压;
- 我自己也在刷题间隙研究过Riverpod,发现它解决了Provider的“BuildContext依赖”痛点,小模块可以用。
📌 真实心声:其实我想上MobX,但领导说“别整那些冷门的,万一你跳槽了谁维护?”
实战:怎么写才不被后人骂?
1. 分层设计,别把逻辑塞进Widget
以前的代码长这样(脱敏后):
class FilterPage extends StatefulWidget {
@override
_FilterPageState createState() => _FilterPageState();
}
class _FilterPageState extends State<FilterPage> {
String selectedCategory = 'all';
bool isLoading = false;
void _fetchData() async {
setState(() { isLoading = true; });
final data = await http.get('/api/data?category=$selectedCategory');
// ...处理数据
setState(() { isLoading = false; });
}
}
这代码在简历上写“独立负责XX模块”没问题,但实际维护起来想哭。现在我把它拆成三层:
- Model层:定义数据结构和API调用(纯Dart,无Flutter依赖)
- ViewModel层:用
ChangeNotifier封装状态和业务逻辑 - View层:只负责UI展示和用户交互
比如爬虫数据的展示模块:
// model/tender_model.dart
class TenderModel {
final String title;
final String url;
TenderModel.fromJson(Map<String, dynamic> json)
: title = json['title'],
url = json['url'];
}
// viewmodel/tender_provider.dart
class TenderProvider with ChangeNotifier {
List<TenderModel> _tenders = [];
bool _isLoading = false;
List<TenderModel> get tenders => _tenders;
bool get isLoading => _isLoading;
Future<void> fetchTenders(String keyword) async {
_isLoading = true;
notifyListeners(); // 先通知loading
try {
final response = await http.get('/crawler/tenders?q=$keyword');
_tenders = (response['data'] as List)
.map((e) => TenderModel.fromJson(e))
.toList();
} finally {
_isLoading = false;
notifyListeners();
}
}
}
然后在main.dart里注册:
void main() {
runApp(
ChangeNotifierProvider<TenderProvider>(
create: (_) => TenderProvider(),
child: MyApp(),
),
);
}
View层就清爽多了:
class TenderListPage extends StatelessWidget {
@override
Widget build(BuildContext context) {
final provider = context.watch<TenderProvider>();
return Scaffold(
body: provider.isLoading
? CircularProgressIndicator()
: ListView.builder(
itemCount: provider.tenders.length,
itemBuilder: (_, i) => ListTile(title: Text(provider.tenders[i].title)),
),
);
}
}
2. 处理跨页面状态同步
产品有个需求:在详情页点击“收藏”,首页列表对应项要实时更新图标。以前的做法是用Navigator.pop传值,或者全局变量,特别脆弱。
现在用Provider的selective rebuild特性:
// 在详情页
final tender = context.read<TenderProvider>().tenders[index];
onPressed: () {
context.read<TenderProvider>().toggleFavorite(tender.id);
// 不需要pop!状态自动同步
}
首页列表监听特定字段:
// 只在favorite状态变化时重建
final isFavorited = context.select<TenderProvider, bool>(
(p) => p.isFavorited(tender.id),
);
性能直接起飞,再也不用担心用户狂点收藏导致页面卡顿。
坑与心得
别在build里创建Provider
曾经手滑写了Provider(create: (_) => MyProvider())放在build方法里,结果每次setState都新建实例,状态全丢。血泪教训!异步操作记得try-finally
网络请求可能失败,但loading状态必须关掉,否则用户以为卡死了。我们吃过亏——去年有一次爬虫接口超时,页面loading转了30秒,被用户投诉到客服部。测试!测试!测试!
国企虽佛系,但上线前还是要过测试流程。我给Provider写了单元测试,mock API返回,验证状态变更。虽然花了半天,但避免了两次线上事故。别过度设计
有个同事非要在登录状态用Bloc,结果写了200行代码就为了存个token。我直接给他换成了SharedPreferences+Provider,10行搞定。记住:简单即正义。
跳槽视角:状态管理是道送分题
最近面了几家大厂,几乎每轮都问状态管理。我直接掏出手机给他们看我们App的重构前后对比——内存占用从400MB降到180MB,帧率稳定60fps。面试官眼睛都亮了。
他们关心的不是你会多少框架,而是是否理解状态的本质:
- 状态应该可预测
- 变更应该可追踪
- 错误应该可恢复
这些,Provider+合理架构都能做到。
结语
在国企写代码,最大的好处是不用996,但挑战是如何在“稳定压倒一切”的文化里推动技术改进。这次状态管理重构,没动deadline,没加需求,纯粹是为了代码可维护性——结果产品反而夸我“用户体验提升了”。
所以啊,别觉得国企就是技术洼地。只要你想,哪怕用最朴实的Provider,也能写出让人眼前一亮的代码。
对了,如果你也在准备跳槽,不妨从重构一个小模块开始。面试时聊这个,比背八股文强多了。
(完)
P.S. 我们App已上架各大应用市场,搜“XX省公共资源交易”就能找到。欢迎体验,但别扒代码,爬虫接口有风控 😅

评论 0