Flutter中传递Dart Setter及LateInitializationError问题求助
Flutter多页面注册流程问题
我正在开发一个多页面注册流程,目前包含姓名页和年龄页。我编写了如下UserModel,期望更新任一字段时触发注册页面重建,从而切换至注册的下一步。我有两个问题:
- 是否可以像代码中这样传递
UserModel的setter?或者有更优的实现方式? - 点击“Next_na”按钮添加姓名时,出现如下错误:
LateInitializationError: Field 'firstName' has not been initialized.
UserModel代码
class UserModel extends ChangeNotifier { late String firstName; late int userAge; int indexer = 0; set addFName(String firstName) { firstName = this.firstName; indexer = indexer + 1; notifyListeners(); } String get fName { return firstName; } set addUAge(int userAge) { userAge = this.userAge; indexer = indexer + 1; notifyListeners(); } int get uAge { return userAge; } }
注册页面代码
@override Widget build(BuildContext context) { return Scaffold( body: ChangeNotifierProvider( create: (context) => UserModel(), child: Center( child: Padding( padding: const EdgeInsets.all(18.0), child: Consumer<UserModel>(builder: (context, user, child) { return Column( mainAxisAlignment: MainAxisAlignment.center, children: [ const Text( "Sign Up", style: TextStyle(fontSize: 24), textAlign: TextAlign.center, ), const Divider( height: 30, endIndent: 20, indent: 20, thickness: 1.5, color: Colors.grey, ), const SizedBox( height: 30, ), if (user.indexer == 0) FirstNameWidget( user: user, ) else FirstNameWidget( user: user, ) ], ); }), )), ); }
FirstNameWidget代码
class FirstNameWidget extends StatelessWidget { FirstNameWidget({Key? key, required this.user}) : super(key: key); final UserModel user; final firstNameController = TextEditingController(); @override Widget build(BuildContext context) { return Form( //key: _firstNameFormKey, child: Column( children: [ TextFormField( keyboardType: TextInputType.text, controller: firstNameController, decoration: const InputDecoration( border: OutlineInputBorder(), hintText: 'Enter First Name', ), //autovalidateMode: AutovalidateMode.onUserInteraction, ), const SizedBox( height: 20, ), SizedBox( width: MediaQuery.of(context).size.width * 0.8, child: ElevatedButton( onPressed: () { print(firstNameController.text); commitFirstName(fName: firstNameController.text, user: user); //user.addFName = firstNameController.text; }, child: const Text('Next_na'), ), ), ], ), ); } } void commitFirstName({required String fName, required UserModel user}) { user.addFName = fName; }
问题解答
问题2:LateInitializationError错误修复
这个错误的核心是UserModel的setter赋值逻辑完全写反,且late修饰的firstName从未被初始化。
原setter代码:
set addFName(String firstName) { firstName = this.firstName; // 错误:把未初始化的成员变量赋值给参数,完全搞反方向 indexer = indexer + 1; notifyListeners(); }
修正后:
set addFName(String firstName) { this.firstName = firstName; // 将参数值赋给类成员变量 indexer += 1; notifyListeners(); }
同理,addUAge setter也要修正:
set addUAge(int userAge) { this.userAge = userAge; indexer += 1; notifyListeners(); }
额外建议:避免用late修饰可能未提前初始化的变量,改用可空类型或默认值更安全:
// 方案1:可空类型 String? firstName; int? userAge; // 方案2:默认值 String firstName = ''; int userAge = 0;
问题1:UserModel传递及优化方案
你当前传递UserModel实例的方式可行,但有更简洁的优化方向:
1. 直接在Widget中通过Provider获取实例
不需要通过构造函数传递user,在FirstNameWidget里直接获取,代码更解耦:
class FirstNameWidget extends StatelessWidget { const FirstNameWidget({Key? key}) : super(key: key); final firstNameController = TextEditingController(); @override Widget build(BuildContext context) { // 不需要监听变化,listen设为false final user = Provider.of<UserModel>(context, listen: false); return Form( child: Column( children: [ // 省略TextFormField代码 ElevatedButton( onPressed: () { user.addFName = firstNameController.text; }, child: const Text('Next_na'), ), ], ), ); } }
此时注册页面调用FirstNameWidget无需传参,且else分支要替换成年龄页Widget:
if (user.indexer == 0) const FirstNameWidget() else const AgeWidget() // 替换为你的年龄页Widget
2. 用普通方法替代setter
对于包含业务逻辑(更新indexer+通知监听)的操作,普通方法可读性更强:
class UserModel extends ChangeNotifier { String firstName = ''; int userAge = 0; int indexer = 0; void setFirstName(String name) { firstName = name; indexer++; notifyListeners(); } void setUserAge(int age) { userAge = age; indexer++; notifyListeners(); } String get fName => firstName; int get uAge => userAge; }
调用时直接用user.setFirstName(firstNameController.text),比setter更直观。
内容的提问来源于stack exchange,提问作者watercroc
相关产品推荐
相关产品推荐

