You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Flutter项目使用Getx+DropdownButtonFormField遇StackOverflowError求助

解决GetX结合Firestore流与DropdownButtonFormField的StackOverflowError问题

问题根源分析

  1. 控制器循环更新触发栈溢出:
    在villagesNamesList()方法中,每次Firestore快照触发时,你直接往villageNames这个RxList里追加元素,并且返回villageNames本身。由于bindStream会监听流的输出并更新villageNames,而villageNames的变化又会触发流的后续处理,形成无限循环,最终导致栈溢出。

  2. 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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.19 02:51:01