Flutter GetX异常:新增分类后Rx对象值监听失效
GetX监听失效问题:新增分类后总值不更新,需修改初始输入框才恢复
问题现象
- 页面首次加载后,输入数值可正常触发总值的监听更新
- 在DateClass中新增分类并输入金额,总值无变化
- 修改第一个输入框的数值后,总值正常更新,且后续第二个输入框的变化也能触发总值更新
- 疑问:是否遗漏了GetX的关键配置?
操作步骤截图
- 页面初始化后输入数值,总值正常监听

- 新增分类输入金额,总值未更新

- 修改第一个输入框,总值正常更新

- 修改第一个数值后,第二个输入框变化触发总值更新

原代码
import 'package:flutter/material.dart'; import 'package:get/get.dart'; import 'package:collection/collection.dart'; class MainClass extends StatefulWidget { Function callback; MainClass({Key key, this.callback}) : super(key: key); @override MainClassState createState() => MainClassState(); } class MainClassState extends State<MainClass> { RxList<DateClass> dynamicPerDate = <DateClass>[].obs; GlobalKey<MainClassState> mKey = GlobalKey(); String stringTotal = ""; addPerDate() async { dynamicPerDate.add(DateClass()); setState(() {}); } calculate() { int total = 0; List<int> listAmount = []; for (int i = 0; i < dynamicPerDate.value.length; i++) { for (int j = 0; dynamicPerDate.value[i].listCategory.length > j; j++) { var a = dynamicPerDate[i].listCategory[j].amountCategory; print(a); if (a != null) { listAmount.add(a.value); } total = listAmount.sum; } } return total.toString(); } @override void initState() { super.initState(); addPerDate(); } @override Widget build(BuildContext context) { return Scaffold( key: mKey, body: Container( child: ListView( children: [ ListView.builder( physics: NeverScrollableScrollPhysics(), shrinkWrap: true, itemCount: dynamicPerDate.length, itemBuilder: (_, index) => dynamicPerDate.isNotEmpty ? dynamicPerDate[index] : Container()), FlatButton( onPressed: () { addPerDate(); }, child: Text('Add Date')), SizedBox(height: 20), Text('Total All Amount From Category Class'), Obx(() => Text(calculate())), ], ), ), ); } } class DateClass extends StatefulWidget { RxList<CategoryClass> listCategory = <CategoryClass>[].obs; DateClass({Key key, this.listCategory}) : super(key: key); @override _DateClassState createState() => _DateClassState(); } class _DateClassState extends State<DateClass> { addCategoryPerDate() { widget.listCategory.add(CategoryClass()); setState(() {}); } @override void initState() { super.initState(); widget.listCategory = <CategoryClass>[].obs; addCategoryPerDate(); } @override Widget build(BuildContext context) { return Padding( padding: const EdgeInsets.all(8.0), child: Card( child: Column( mainAxisAlignment: MainAxisAlignment.start, children: [ Text('Date', style: TextStyle(color: Colors.blue)), ListView.builder( physics: NeverScrollableScrollPhysics(), shrinkWrap: true, itemCount: widget.listCategory.length, itemBuilder: (_, index) => widget.listCategory.isNotEmpty ? widget.listCategory[index] : Container()), FlatButton( onPressed: () { addCategoryPerDate(); }, child: Text('Add Category')) ], ), ), ); } } class CategoryClass extends StatefulWidget { RxInt amountCategory = 0.obs; TextEditingController amountController; CategoryClass({Key key, this.amountCategory}) : super(key: key); @override _CategoryClassState createState() => _CategoryClassState(); } class _CategoryClassState extends State<CategoryClass> { MainClass mainClass = MainClass(); @override void initState() { super.initState(); widget.amountCategory = 0.obs; } @override Widget build(BuildContext context) { return Column( mainAxisAlignment: MainAxisAlignment.start, children: [ Text('Amount'), TextFormField( controller: widget.amountController, onChanged: (value) { setState(() { widget.amountCategory.value = int.parse(value); widget.amountCategory.obs; }); }, keyboardType: TextInputType.number, ) ], ); } }
问题根源与修复方案
核心问题
- Rx对象重复初始化:在
DateClass和CategoryClass的initState中重新赋值Rx对象(如widget.listCategory = <CategoryClass>[].obs;),导致MainClass中原来的RxList引用被替换,无法跟踪后续变化。 - GetX与setState混用:Rx对象的更新不需要依赖setState,混用会破坏GetX的响应式监听逻辑。
- 监听层级缺失:MainClass的
Obx仅监听了dynamicPerDate的变化,但未感知内部listCategory的新增和amountCategory的更新(新增的Category的Rx对象未被纳入监听依赖)。
修复步骤
1. 修正DateClass
- 移除
initState中重新赋值widget.listCategory的代码,保留默认初始化或传入的RxList - 删除
addCategoryPerDate中的setState,直接利用RxList的响应式更新
class DateClass extends StatefulWidget { RxList<CategoryClass> listCategory = <CategoryClass>[].obs; DateClass({Key key, this.listCategory}) : super(key: key); @override _DateClassState createState() => _DateClassState(); } class _DateClassState extends State<DateClass> { addCategoryPerDate() { widget.listCategory.add(CategoryClass()); } @override void initState() { super.initState(); addCategoryPerDate(); } // build方法不变 }
2. 修正CategoryClass
- 移除
initState中重新赋值widget.amountCategory的代码 - 移除
onChanged中的setState和多余的widget.amountCategory.obs;,直接更新Rx对象的value,同时初始化文本控制器避免空指针
class CategoryClass extends StatefulWidget { RxInt amountCategory = 0.obs; TextEditingController amountController = TextEditingController(); CategoryClass({Key key, this.amountCategory}) : super(key: key); @override _CategoryClassState createState() => _CategoryClassState(); } class _CategoryClassState extends State<CategoryClass> { @override void initState() { super.initState(); } @override Widget build(BuildContext context) { return Column( mainAxisAlignment: MainAxisAlignment.start, children: [ Text('Amount'), TextFormField( controller: widget.amountController, onChanged: (value) { widget.amountCategory.value = int.tryParse(value) ?? 0; }, keyboardType: TextInputType.number, ) ], ); } }
3. 修正MainClass
- 移除
addPerDate中的setState,利用RxList的响应式更新 - 简化
calculate方法,确保访问所有Rx对象的.value,让Obx自动收集所有依赖
class MainClassState extends State<MainClass> { RxList<DateClass> dynamicPerDate = <DateClass>[].obs; GlobalKey<MainClassState> mKey = GlobalKey(); String stringTotal = ""; addPerDate() { dynamicPerDate.add(DateClass()); } calculate() { int total = 0; for (final dateItem in dynamicPerDate) { for (final categoryItem in dateItem.listCategory) { total += categoryItem.amountCategory.value; } } return total.toString(); } // initState和build方法不变 }
修复后效果
- 新增分类并输入金额时,总值会实时更新
- 所有输入框的变化都能直接触发总值更新,无需依赖初始输入框的修改
内容的提问来源于stack exchange,提问作者Soveyyy
相关产品推荐
相关产品推荐

