静态布尔字段值未随其他类中条件正确变化的问题
静态布尔变量状态不一致问题排查与解决
问题描述
我编写了一个修改静态布尔变量的方法,希望根据该变量状态条件显示按钮组件:满足条件时设为true,否则设为false。方法内部打印变量值符合预期,但从其他类调用时,值却经常不符合预期——有时条件不满足仍显示true,满足时反而显示false。
相关代码
定义静态布尔变量的类
class GetBool { // 要修改的静态变量 static bool? isAdded; }
修改静态变量的方法
void getBool(String model) async { print("function ran"); User? user = FirebaseAuth.instance.currentUser; DocumentSnapshot<Map<String, dynamic>> document = await FirebaseFirestore .instance .collection("Cart") .doc(user!.uid) .get(); List list = []; for (var doc in document.data()!['cart'] as Iterable) { list.add(doc['model']); print("model says before condition $model"); print("list is $list"); if (list.contains(model)) { GetBool.isAdded = true; print("this item exist"); print(GetBool.isAdded); } else { GetBool.isAdded = false; print("this item doesnt exist"); print(GetBool.isAdded); } } }
调用方法的位置
class WatchTile extends StatefulWidget { final Watch? watch; const WatchTile({this.watch, super.key}); @override State<WatchTile> createState() => _WatchTileState(); } class _WatchTileState extends State<WatchTile> { @override Widget build(BuildContext context) { return GestureDetector( onTap: () { Navigator.pushNamed( context, "/watch_details", arguments: widget.watch, ); // 跳转时调用方法 DatabaseService().getBool(widget.watch!.model!); }, child: Container( decoration: BoxDecoration( border: Border.all(color: Colors.black), ), child: Column( children: <Widget>[ Container( height: 200, decoration: BoxDecoration( image: DecorationImage( image: NetworkImage(widget.watch!.image!), fit: BoxFit.cover)), ), Container( padding: const EdgeInsets.only(left: 4.0), width: double.maxFinite, child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( widget.watch!.brand!, style: const TextStyle(color: Colors.grey), ), Text(widget.watch!.model!), Text('\$${widget.watch!.price!}'), ], ), ) ], ), ), ); } }
使用静态变量的页面
final FirebaseAuth auth = FirebaseAuth.instance; User? user = auth.currentUser; class WatchDetail extends StatefulWidget { const WatchDetail({super.key}); @override State<WatchDetail> createState() => _WatchDetailState(); } class _WatchDetailState extends State<WatchDetail> { final DatabaseService _database = DatabaseService(); int itemQuantity = 1; @override Widget build(BuildContext context) { print("getbool says ${GetBool.isAdded}"); final watch = ModalRoute.of(context)?.settings.arguments as Watch; print("route args is ${watch.brand}"); return Scaffold( appBar: AppBar( title: Text(watch.brand!), ), body: Column( children: <Widget>[ Row( mainAxisAlignment: MainAxisAlignment.center, children: [ Container( // 根据静态变量条件显示按钮 child: GetBool.isAdded == false ? ElevatedButton( style: ButtonStyle(), onPressed: () async { await _database.addToCart(watch.model!, watch.brand!, itemQuantity, int.parse(watch.price!)); }, child: Text("Add To Cart"), ) : ElevatedButton( onPressed: () {}, child: Text("Added To Cart")), ), ], ) ], ), ); } }
问题原因分析
- 异步时序错误:
WatchTile的onTap中先执行页面跳转,再调用异步的getBool方法。跳转后WatchDetail的build会立即执行,此时getBool还未完成Firestore查询,GetBool.isAdded还是旧值或初始null,导致显示异常。 - 全局静态变量状态污染:静态变量是全局共享的,多个商品页面的异步操作会互相覆盖值。比如快速切换商品时,前一个请求的结果可能晚于新请求返回,覆盖正确状态。
- 循环逻辑错误:
getBool中循环遍历购物车每个item,每次循环都会更新isAdded,最终状态由最后一个item的判断结果决定,而非整体购物车是否包含目标商品。
解决方案
1. 修复getBool方法逻辑
去掉冗余循环,直接判断购物车列表是否包含目标商品,同时改为返回Future<bool>,避免依赖全局静态变量:
Future<bool> getBool(String model) async { User? user = FirebaseAuth.instance.currentUser; if (user == null) return false; DocumentSnapshot<Map<String, dynamic>> document = await FirebaseFirestore .instance .collection("Cart") .doc(user.uid) .get(); List cartItems = document.data()?['cart'] ?? []; // 直接判断是否存在目标商品 bool isAdded = cartItems.any((item) => item['model'] == model); print("this item ${isAdded ? 'exist' : 'doesnt exist'}"); return isAdded; }
2. 调整页面跳转的异步时序
在WatchTile中等待getBool完成后,将结果作为参数传递给下一页:
onTap: () async { bool isAdded = await DatabaseService().getBool(widget.watch!.model!); Navigator.pushNamed( context, "/watch_details", arguments: { 'watch': widget.watch, 'isAdded': isAdded, }, ); }
3. 在WatchDetail中本地维护状态
接收传递的参数,或者用FutureBuilder在页面内部获取状态,避免全局变量:
class _WatchDetailState extends State<WatchDetail> { final DatabaseService _database = DatabaseService(); int itemQuantity = 1; @override Widget build(BuildContext context) { final args = ModalRoute.of(context)?.settings.arguments as Map; final Watch watch = args['watch']; final bool initialIsAdded = args['isAdded']; return Scaffold( appBar: AppBar(title: Text(watch.brand!)), body: Column( children: <Widget>[ FutureBuilder<bool>( future: _database.getBool(watch.model!), initialData: initialIsAdded, builder: (context, snapshot) { if (snapshot.connectionState == ConnectionState.waiting) { return CircularProgressIndicator(); } bool isAdded = snapshot.data ?? false; return ElevatedButton( onPressed: isAdded ? null : () async { await _database.addToCart( watch.model!, watch.brand!, itemQuantity, int.parse(watch.price!) ); // 添加后刷新状态 setState(() {}); }, child: Text(isAdded ? "Added To Cart" : "Add To Cart"), ); }, ), ], ), ); } }
注意事项
- 避免用全局静态变量管理页面状态,异步场景下极易引发状态混乱。
- 页面状态尽量由自身维护,或使用Provider、Riverpod等专门的状态管理工具。
- 异步操作必须保证时序正确,确保数据准备完成后再更新UI。
内容的提问来源于stack exchange,提问作者Abdullahi Abbas
相关产品推荐
相关产品推荐

