Flutter使用awesome_select报错:S2SingleSelection释放后仍被调用
解决S2SingleSelection已释放后仍被使用的错误
问题根源
错误出在自定义choiceBuilder的两个GestureDetector逻辑中:你手动修改_selectedLevel并调用setState,同时又调用item.onModalClose(true)和item.closeModal()关闭模态。这种操作会导致组件状态更新与模态关闭逻辑冲突——模态关闭后内部的S2SingleSelection实例已被释放,但后续的setState触发组件重建时,会试图再次使用已释放的实例,从而抛出错误。
解决方案
1. 复用组件内置的选择逻辑
不要手动处理选择状态和模态关闭,而是交给SmartSelect.single的onChange回调和item.onTap()方法处理,这是组件设计的标准用法,能避免状态不一致。
2. 移除冗余无效代码
删除选择逻辑中手动更新状态、关闭模态的代码,以及删除逻辑中无效的setState(() { isSelected.value; });语句。
修改后的完整代码
String? _selectedLevel; final firestore = FirebaseFirestore.instance; SmartSelect.single( selectedValue: _selectedLevel, onChange: (newValue) { setState(() { _selectedLevel = newValue.value; }); }, choiceItems: documents.map((DocumentSnapshot<dynamic> dataDoc) { return S2Choice( value: dataDoc.data()['field1'], title: dataDoc.data()['field1'], ); }).toList(), placeholder: 'N/A', tileBuilder: (context, value) { return Container( padding: EdgeInsets.symmetric( vertical: MediaQuery.of(context).size.height * 0.01, horizontal: MediaQuery.of(context).size.width * 0.03, ), decoration: BoxDecoration( color: Theme.of(context).colorScheme.onPrimary, borderRadius: BorderRadius.circular(20), ), child: Row( children: [ Padding( padding: EdgeInsets.symmetric( horizontal: MediaQuery.of(context).size.width * 0.035, ), child: Icon( FontAwesomeIcons.locationDot, color: Theme.of(context).colorScheme.primary, size: MediaQuery.of(context).size.width * 0.065, ), ), Expanded( child: S2Tile( value: Text( _selectedLevel != null ? "" : "", style: TextStyle( color: Theme.of(context).colorScheme.primary, fontSize: MediaQuery.of(context).size.width * 0.055, ), ), onTap: () { value.showModal(); }, title: Text( _selectedLevel != null ? _selectedLevel! : "Choose", style: TextStyle( fontSize: MediaQuery.of(context).size.width * 0.055, color: Theme.of(context).colorScheme.primary, overflow: TextOverflow.ellipsis, ), ), loadingText: "", trailing: Icon( FontAwesomeIcons.angleDown, color: Theme.of(context).colorScheme.primary, ), ), ) ], ), ); }, modalConfig: const S2ModalConfig( title: '', type: S2ModalType.bottomSheet, ), choiceConfig: S2ChoiceConfig( type: S2ChoiceType.radios, style: S2ChoiceStyle( showCheckmark: true, color: Theme.of(context).colorScheme.primary, titleStyle: TextStyle( fontSize: MediaQuery.of(context).size.width * 0.055, color: Theme.of(context).colorScheme.primary, ), ), ), choiceBuilder: (context, item, isSelected) { return Padding( padding: EdgeInsets.symmetric( vertical: MediaQuery.of(context).size.height * 0.015, horizontal: MediaQuery.of(context).size.width * 0.03, ), child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ // 使用组件内置onTap处理选择逻辑 GestureDetector( onTap: item.onTap, child: Row( children: [ Icon( _selectedLevel == isSelected.value ? FontAwesomeIcons.solidCircleCheck : FontAwesomeIcons.circle, color: Theme.of(context).colorScheme.primary, size: MediaQuery.of(context).size.width * 0.055, ), SizedBox( width: MediaQuery.of(context).size.width * 0.05, ), Text( isSelected.value, style: TextStyle( overflow: TextOverflow.ellipsis, fontSize: MediaQuery.of(context).size.width * 0.055, color: Theme.of(context).colorScheme.primary, ), ), ], ), ), Row( children: [ GestureDetector( onTap: () { // TODO EDIT NAME SITE }, child: Icon( FontAwesomeIcons.penToSquare, color: Theme.of(context).colorScheme.primary, size: MediaQuery.of(context).size.width * 0.055, ), ), SizedBox( width: MediaQuery.of(context).size.width * 0.05, ), GestureDetector( onTap: () { if (isSelected.value != null) { CRUDMethodFirestore( selectedLevel: isSelected.value, itemModal: item, context: context, ).delete(); } setState(() { _selectedLevel = null; }); }, child: Icon( FontAwesomeIcons.trash, color: Theme.of(context).colorScheme.primary, size: MediaQuery.of(context).size.width * 0.055, ), ), ], ) ], ), ); }, ),
关键修改说明
- 选择区域的
GestureDetector直接绑定item.onTap,让组件内部完成选择、状态更新和模态关闭的全流程,避免手动操作导致的实例释放冲突。 - 删除了选择逻辑中手动设置
_selectedLevel和调用item.onModalClose、item.closeModal的代码。 - 移除了删除逻辑中无效的
setState语句。
内容的提问来源于stack exchange,提问作者Corentin
相关产品推荐
相关产品推荐

