Flutter DropdownButton选择选项后崩溃:多匹配值错误问题求助
你遇到的这个报错,核心原因是Flutter无法正确判断DropdownMenuItem的value和_selectedLab是否匹配,或者在选项列表中存在多个被判定为和_selectedLab相等的项。下面分步骤给你解决:
1. 重写Partner类的相等性判断方法
Flutter默认用对象的引用地址来判断两个对象是否相等(也就是==运算符默认比较内存地址)。你的AllPathLab()每次请求都会返回新的Partner实例,即使是同一个实验室的数据,新实例和之前选中的_selectedLab实例也会被认为是不同的对象。这就导致DropdownButton在重新构建时,找不到和_selectedLab匹配的选项,从而触发报错。
解决方法是在Partner类中重写==运算符和hashCode,基于唯一标识(比如encPartnerId,这应该是每个实验室的唯一ID)来判断相等:
class Partner { final String encPartnerId; final String partnerName; // 其他属性... Partner({required this.encPartnerId, required this.partnerName/*, 其他参数*/}); // 重写==运算符 @override bool operator ==(Object other) { if (identical(this, other)) return true; return other is Partner && other.encPartnerId == encPartnerId; } // 重写hashCode @override int get hashCode => encPartnerId.hashCode; }
这样,只要两个Partner对象的encPartnerId相同,就会被判定为相等,不管是不是同一个实例。
2. 避免FutureBuilder重复发起请求
你当前的代码中,FutureBuilder的future参数直接传AllPathLab(),这会导致每次组件build时都创建一个新的Future,重复发起网络请求——不仅浪费资源,还可能导致列表数据频繁刷新,加重相等性判断的问题。
可以把Future对象存在state变量中,在initState时初始化:
class _MultipleTestBookingState extends State<MultipleTestBooking> { Partner? _selectedLab; Datum? _selectedTest; late Future<List<Partner>> _labFuture; // 声明Future变量 @override void initState() { super.initState(); _labFuture = AllPathLab(); // 在initState中初始化Future } // ...其他代码 @override Widget build(BuildContext context) { return Container( child: FutureBuilder<List<Partner>>( future: _labFuture, // 使用初始化好的Future builder: (BuildContext context, AsyncSnapshot snapshot) { // ...原有的builder逻辑 }, ), ); } }
这样只会在组件初始化时发起一次请求,后续build不会重复请求,也能保证列表数据的稳定性。
3. 可选:添加空值判断,增强鲁棒性
在DropdownButton的value参数中,确保_selectedLab确实存在于当前的选项列表中(虽然重写相等性后这个概率很低,但可以进一步避免报错)。可以在构建DropdownButton前做个判断:
if (snapshot.hasData) { final labList = snapshot.data as List<Partner>; // 检查_selectedLab是否在列表中,不在的话设为null final isValidSelected = labList.contains(_selectedLab); return DropdownButton<Partner>( value: isValidSelected ? _selectedLab : null, hint: Text("Select Lab"), items: labList.map((Partner data) => DropdownMenuItem<Partner>( child: Text("${data.partnerName}"), value: data, ) ).toList().cast<DropdownMenuItem<Partner>>(), onChanged: (value){ setState(() { _selectedLab=value; encLabId = value!.encPartnerId; GetTestByLab(); }); } ); }
这样即使出现意外情况,也能保证DropdownButton有合法的value值,避免崩溃。
按照这几步修改后,你的下拉菜单应该就能正常工作,不会再出现选择后崩溃的问题了。
内容的提问来源于stack exchange,提问作者Toujo

