无状态Widget结合Bloc使用ImagePicker为何触发LateInitializationError?
问题描述
使用ImagePicker选择图片功能正常,但将图片传入Bloc的sink时程序崩溃,报错:
LateInitializationError: Field '_textSeparators@411091221' has already been initialized.
移除FormBuilder后功能恢复正常,逐步添加组件排查发现,TextFieldTags组件是引发错误的根源。
相关代码片段
Widget代码
class CreatePost extends StatelessWidget { final GlobalKey<FormBuilderState> _formkey = GlobalKey<FormBuilderState>(debugLabel: 'GlobalFormKey #SignIn '); const CreatePost({required Key key}) : super(key: key); @override Widget build(BuildContext context) { return BlocBuilder<PostBloc, PostState>( builder: (context, state) { if (state is AddImagePost) { return Scaffold( appBar: AppBar( iconTheme: const IconThemeData(color: Colors.black,), ), body: GestureDetector( onTap: () { ImagePicker().pickImage( source: ImageSource.gallery,) .then((im) =>context.read<PostBloc>().add(SetImagePost(im!))); }, child: Column( children: [ FormBuilder(key: _formkey, child: /* 省略其他组件 */), _imageWidget(state.memoryImage), ], ), ),); } // 补充其他状态的返回逻辑 return const SizedBox(); }, ); } }
Event代码
class SetImagePost extends PostEvent { const SetImagePost(this.image); final XFile image; }
State代码
class AddImagePost extends PostState { final MemoryImage memoryImage; AddImagePost(this.memoryImage) : super(); }
Bloc代码
class PostBloc extends Bloc<PostEvent, PostState> { final XFile image; PostBloc({required this.image}) :super(CreatePostInit()){ on<SetImagePost>(_setImagePost); } void _setImagePost(SetImagePost event, Emitter<PostState> emit) async { var memoryImage = await apiRepository.postImage(event.image); emit(AddImagePost(memoryImage)); } }
引发错误的TextFieldTags组件代码
TextFieldTags( textfieldTagsController: tagsControllerAnswers, initialTags: const ["yes","no","maybe"], textSeparators: const [' ', ','], letterCase: LetterCase.small, validator: (String tag) { if (tagsController.getTags!.contains(tag)) { return 'you already entered that'; } if(tagsControllerAnswers.getTags!.length > 4){ return 'Please enter no more than 5 tags.'; } return null; }, inputfieldBuilder: (context, tec, fn, error, onChanged, onSubmitted) { return ((context, sc, tags, onTagDelete) { return TextField( controller: tec, focusNode: fn, decoration: InputDecoration( isDense: true, focusedBorder: const OutlineInputBorder( borderSide: BorderSide(color: askTextFieldBorderFocused, width: 3.0), ), enabledBorder: const OutlineInputBorder( borderSide: BorderSide(color: askTextFieldBorder, width: 2.0), ), errorText: error, prefixIconConstraints: BoxConstraints(maxWidth: MediaQuery.of(context).size.width * 0.74), prefixIcon: tags.isNotEmpty ? SingleChildScrollView( controller: sc, scrollDirection: Axis.horizontal, child: Row( children: tags.map((String tag) { return Container( decoration: const BoxDecoration( borderRadius: BorderRadius.all( Radius.circular(3.0), ), color: tagColor, ), margin: const EdgeInsets.symmetric( horizontal: 5.0), padding: const EdgeInsets.symmetric( horizontal: 5.0, vertical: 5.0), child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ InkWell( child: Text( tag, style: CustomTextStyle.bodyText1(context)?.copyWith(color: tagFont ), ), onTap: () { // print("$tag selected"); }, ), const SizedBox(width: 3.0), InkWell( child: const Icon( Icons.close_rounded, size: 20.0, color: tagFont, ), onTap: () { onTagDelete(tag); }, ) ], ), ); }).toList()), ) : null, ), onChanged: onChanged, onSubmitted: onSubmitted, ); }); }, ),
排查方向建议
- 检查
tagsControllerAnswers的生命周期:如果控制器是全局变量或在StatelessWidget中被复用,可能导致重复初始化冲突。将CreatePost改为StatefulWidget,在initState中初始化控制器,dispose方法中销毁,确保每次重建都使用新的控制器实例或正确管理状态。 - 确认TextFieldTags与FormBuilder的集成方式:确保TextFieldTags被正确包装在FormBuilderField中,未正确注册到FormBuilder会导致Form重建时组件内部状态异常。
- 检查Bloc状态更新后的重建逻辑:Bloc emit新状态后,整个Scaffold会重建,若TextFieldTags的
textSeparators等字段被重复赋值给已初始化的内部变量,会触发LateInitializationError。尝试将这些配置提取为全局常量,或确保组件重建时不会重复初始化内部字段。 - 排查TextFieldTags组件的版本问题:该错误指向组件内部的
_textSeparators字段重复初始化,可能是组件版本存在已知bug,尝试升级到最新稳定版或降级到之前的可用版本。 - 验证Bloc的初始化逻辑:PostBloc的构造函数接收
image参数,确认Bloc是否在状态更新时被重复创建,导致依赖的组件状态紊乱。确保Bloc是通过BlocProvider全局提供,而非在build方法中重复实例化。
内容的提问来源于stack exchange,提问作者midi
相关产品推荐
相关产品推荐

