Flutter中FutureBuilder加载SharedPreferences数据给DropDownButton赋值报错问题
问题根因
这个报错是Flutter DropdownButton的强制校验规则触发:要求绑定的value必须在items的value集合中存在且唯一,触发场景有两种:
- 当前绑定的
dropdownValue不在异步加载回来的下拉选项值列表中 - 下拉选项值列表存在重复值
解决步骤
- 校验下拉值合法性
异步拿到下拉列表后先做合法性校验,如果当前dropdownValue不在列表中,自动重置为列表第一个值,避免匹配失败。 - 避免Future重复执行
不要把getDropDownItems()直接写在FutureBuilder的future参数中,每次组件刷新都会生成新的Future实例导致状态异常,建议在initState中提前初始化Future变量。 - 列表去重
生成下拉选项前先对列表去重,避免重复值导致匹配到多个结果。 - 索引取值适配
选择下拉选项后不要用全局的konzernDataTitle找索引,要以实际加载的当前列表为准,避免本地存储的列表和全局列表内容不一致导致索引错位。
代码修改示例
1. 状态变量与初始化
class _YourPageState extends State<YourPage> { late Future<List<DropdownMenuItem<String>>> _dropDownItemsFuture; String? dropdownValue; // 其余原有变量保持不变 @override void initState() { super.initState(); _dropDownItemsFuture = getDropDownItems(); } // 其余原有代码 }
2. 优化getDropDownItems方法
Future<List<DropdownMenuItem<String>>> getDropDownItems() async { SharedPreferences prefs = await SharedPreferences.getInstance(); List<String> actualList; if (prefs.containsKey("prefsKonzernTitle")) { actualList = prefs.getStringList("prefsKonzernTitle") ?? konzernDataTitle; } else { actualList = konzernDataTitle; } // 列表去重 final uniqueList = actualList.toSet().toList(); return uniqueList.map((data) { return DropdownMenuItem<String>( value: data, child: Text(data), ); }).toList(); }
3. 优化FutureBuilder组件
FutureBuilder<List<DropdownMenuItem<String>>>( future: _dropDownItemsFuture, builder: (context, snapshot) { if (!snapshot.hasData) { return const SizedBox(); } final items = snapshot.data!; final valueList = items.map((e) => e.value).toList(); // 校验值合法性 if (dropdownValue == null || !valueList.contains(dropdownValue)) { dropdownValue = valueList.first; } return DropdownButton<String>( value: dropdownValue, items: items, onChanged: (String? newValue) { if (newValue == null) return; setState(() { dropdownValue = newValue; int index = valueList.indexOf(newValue); // 如果关联的link、image等数据也存在本地,需要先取出本地存储的对应列表再取值 titleController.text = valueList[index]; }); }, ); } )
内容的提问来源于stack exchange,提问作者Thoxh
相关产品推荐
相关产品推荐

