Flutter TextField值变更触发setter时App冻结栈溢出问题
问题根因
触发栈溢出导致应用冻结的核心原因是CalculationService中areaInMeterSquared的setter存在无限递归调用,同时属性定义存在语法级错误。
错误点明细
- setter递归死循环:setter方法内部写的
areaInMeterSquared = state,本质是再次调用了areaInMeterSquared的setter本身,而不是给存储值的变量赋值,代码会无限循环执行setter逻辑直到栈空间耗尽,正好对应捕获到的Stack Overflow报错。 - 私有属性被错误声明为
final:用来存储输入值的_areaInMeterSquared等属性都加了final修饰,这类变量初始化后不允许重新赋值,就算修正了setter的赋值目标,代码也会报编译错误。 - 输入框逻辑隐患:现有
TextFormField仅通过initialValue做初始赋值,状态刷新时输入框不会同步最新值,且int.parse没有做异常兜底,用户输入非数字、清空内容时会直接抛格式转换异常。
修复方案
- 移除所有输入值对应私有属性的
final关键字,允许变量重新赋值 - 修正setter内部的赋值逻辑,将值赋给私有变量
_areaInMeterSquared,避免递归调用 - 给输入框增加格式解析兜底,避免解析异常崩溃
修正后的CalculationService核心代码如下:
class CalculationService with ChangeNotifier { late final SharedPreferences sharedPreferences; // 移除final关键字,允许后续修改值 int _areaInMeterSquared = 0; int _basicRentForUnit = 0; int _installmentsPerYear = 0; int _tenantCustomizations = 0; int _technicalUpgrades = 0; CalculationService(this.sharedPreferences); final double rateOfReturn = 0.02; final double inflation = 0.05; final int tenantCustomizationYears = 5; final int technicalUpgradeYears = 20; int get areaInMeterSquared => _areaInMeterSquared; int get basicRentForUnit => _basicRentForUnit; int get installmentsPerYear => _installmentsPerYear; int get tenantCustomizations => _tenantCustomizations; int get technicalUpgrades => _technicalUpgrades; set areaInMeterSquared(int state) { sharedPreferences.setInt(areaInMeterSquaredKey, state); // 给私有变量赋值,禁止调用setter自身 _areaInMeterSquared = state; notifyListeners(); } // 其余属性的setter参考上述逻辑实现即可 }
输入框部分增加解析兜底的参考写法:
TextFormField( initialValue: calculationService.areaInMeterSquared.toString(), keyboardType: TextInputType.number, onChanged: (text) { // 解析失败时默认赋值0,避免崩溃 final parsedValue = int.tryParse(text) ?? 0; calculationService.areaInMeterSquared = parsedValue; }, ),
如果需要状态刷新时输入框内容完全同步,建议使用TextEditingController做双向绑定,替代initialValue的静态初始化方式。
内容的提问来源于stack exchange,提问作者ANicholasson
相关产品推荐
相关产品推荐

