Flutter项目使用Getx+DropdownButtonFormField遇StackOverflowError求助
问题根源分析
控制器循环更新触发栈溢出:
在villagesNamesList()方法中,每次Firestore快照触发时,你直接往villageNames这个RxList里追加元素,并且返回villageNames本身。由于bindStream会监听流的输出并更新villageNames,而villageNames的变化又会触发流的后续处理,形成无限循环,最终导致栈溢出。UI回调写法错误:
onChanged参数直接调用addEmployeeController.changeDropdownValue(value),这会在Widget构建时立即执行方法,而非在下拉选项变化时触发,可能引发额外的状态更新问题。
修复方案
1. 修正控制器代码
修改流处理逻辑,每次快照生成新列表,避免直接操作RxList导致循环:
class AddEmployeeController extends GetxController { final CollectionReference _villagesCollectionRef = FirebaseFirestore.instance.collection('Categories'); RxList<String> villageNames = RxList([]); RxString startingVillageName = ''.obs; final formKey = GlobalKey<FormState>(); @override void onInit() { super.onInit(); villageNames.bindStream(villagesNamesList()); } Stream<List<String>> villagesNamesList() { return _villagesCollectionRef.snapshots().map((QuerySnapshot query) { // 每次快照生成全新列表,不直接修改villageNames return query.docs.map((doc) => doc['name'] as String).toList(); }); } void changeDropdownValue(String? newValue) { if (newValue != null) { startingVillageName.value = newValue; } } }
2. 修正UI代码
调整onChanged为正确的回调形式,并确保Rx变量使用.value获取当前值:
class CreateAccount extends StatelessWidget { CreateAccount({Key? key}) : super(key: key); final AddEmployeeController addEmployeeController = Get.put(AddEmployeeController()); @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( backgroundColor: AppColors.mainColor, title: titleText( text: 'Create Account', size: Dimensions.font20, ), centerTitle: true, ), body: Form( key: addEmployeeController.formKey, child: Column( children: [ SizedBox(height: Dimensions.height40), Row( mainAxisAlignment: MainAxisAlignment.center, children: [ Obx( () => SizedBox( width: Dimensions.width200, child: DropdownButtonFormField<String>( focusColor: AppColors.whiteColor, icon: const Icon(Icons.arrow_circle_down_rounded), decoration: inputDecoration(), // 空值时设为null,避免Dropdown选项不匹配报错 value: addEmployeeController.startingVillageName.value.isEmpty ? null : addEmployeeController.startingVillageName.value, items: addEmployeeController.villageNames .map((item) => DropdownMenuItem<String>( value: item, child: Text(item), )) .toList(), // 传递函数引用,仅在选项变化时触发 onChanged: addEmployeeController.changeDropdownValue, ), ), ) ], ), ], ), ), ); } }
关键说明
- 流处理时始终返回新列表,让
bindStream自动更新RxList,彻底避免手动修改引发的循环更新。 DropdownButtonFormField的value必须是列表中存在的有效值或null,否则会抛出选项不匹配的错误。onChanged必须传入函数引用,而非执行方法的结果,确保仅在用户选择选项时触发状态更新。
内容的提问来源于stack exchange,提问作者Muhammad Qazmouz
相关产品推荐
相关产品推荐

