Flutter DropdownButton断言错误求助:API加载下拉选项触发异常
问题详情
通过API拉取数据填充Flutter的DropdownButton时,其他流程正常,但加载下拉菜单时触发断言错误:
Exception has occurred.
_AssertionError ('package:flutter/src/material/dropdown.dart': Failed assertion: line 892 pos 15: 'items == null || items.isEmpty || value == null ||
items.where((DropdownMenuItemitem) {
return item.value == value;
}).length == 1': There should be exactly one item with [DropdownButton]'s value: .
Either zero or 2 or more [DropdownMenuItem]s were detected with the same value)
对应的代码片段如下:
Dropdown代码
child: DropdownButton<String>( value: _mystate, iconSize: 30, icon: (null), style: const TextStyle( color: Colors.black54, fontSize: 16, ), hint: Text("Lütfen Seçim Yapınız"), onChanged: (String? newValue) { setState(() { _mystate=newValue.toString(); sevkikayatListesi(); print(_mystate); }); }, items: _items.map((item) { return DropdownMenuItem( child: Text(item.CARIISIM.toString()), value: item.YUKLEMENO, ); })?.toList()??[], )
API请求代码
sevkikayatListesi() async { final response = await Dio().get('http://192.168.0.21/api/values/Degerler'); if (response.statusCode == HttpStatus.ok) { final _datas = response.data; if (_datas is List) { setState(() { _items = _datas.map((e) => PaletToplamaGrid.fromJson(e)).toList(); }); } } }
变量定义
List<PaletToplamaGrid> _items = []; String _mystate = "";
错误原因分析
- 初始值不匹配:
_mystate初始值是空字符串"",但API返回的_items中没有value为空字符串的选项,DropdownButton找不到对应值的条目,触发断言。 - 重复value值:API返回的
YUKLEMENO字段存在重复,导致多个DropdownMenuItem的value相同,违反了DropdownButton“每个value对应唯一选项”的规则。 - 数据加载时机问题:初始时
_items为空,但_mystate有值,DropdownButton无法匹配到任何选项。
解决步骤
1. 修正初始值为null
把_mystate的初始值从空字符串改成null,这样当_items为空时,DropdownButton会显示hint,不会因为找不到对应选项报错:
String? _mystate = null;
同时适配DropdownButton的可空类型:
DropdownButton<String?>( value: _mystate, // 其他代码不变 onChanged: (String? newValue) { setState(() { _mystate = newValue; // 若无需每次选择都重新加载API,可移除sevkikayatListesi() print(_mystate); }); }, )
2. 确保value值唯一
检查API返回的YUKLEMENO字段是否重复:
- 若为后端问题,联系后端修复,确保每个
YUKLEMENO唯一; - 若需前端临时处理,加载数据时去重:
setState(() { final uniqueMap = <String, PaletToplamaGrid>{}; for (var e in _datas) { final item = PaletToplamaGrid.fromJson(e); uniqueMap[item.YUKLEMENO] = item; } _items = uniqueMap.values.toList(); });
3. 数据加载后设置默认选中项(可选)
如果需要页面加载完成后默认选中第一个选项,在API请求成功后添加逻辑:
if (_datas is List) { setState(() { _items = _datas.map((e) => PaletToplamaGrid.fromJson(e)).toList(); if (_items.isNotEmpty) { _mystate = _items.first.YUKLEMENO; } }); }
4. 优化onChanged逻辑
原代码中每次选择选项都会重新加载API,这通常不必要,若无需刷新下拉列表,直接移除sevkikayatListesi()即可。
内容的提问来源于stack exchange,提问作者Ahmet Enes Söylemez

