Flutter中如何缓存多选下拉框选中项并在返回应用时预填充
我仔细看了你的代码和遇到的问题,你碰到的Lookup failed: SharedPreferences错误主要是因为重复获取SharedPreferences实例、RxList赋值逻辑的小问题,再加上回调里的一些疏漏,咱们一步步来解决:
1. 修复SharedPreferences实例重复获取的问题
你的QuestionnaireController已经通过构造函数拿到了preferences实例,但在loadSelectedChoices方法里又重新调用await SharedPreferences.getInstance(),这不仅多余,还可能导致实例冲突引发查找失败。直接用控制器里已有的实例即可:
Future<void> loadSelectedChoices() async { // 移除重复的实例获取代码 // SharedPreferences prefs = await SharedPreferences.getInstance(); List<String>? loadedChoices = preferences.getStringList('selected_choices'); if (loadedChoices != null) { print("loading choices"); print(choices.value); // 用assignAll更新已有RxList的内容,而非创建新实例 choices.assignAll(loadedChoices); } }
2. 修正RxList的赋值逻辑
之前你用choices.value = loadedChoices.obs;,这相当于给choices赋值了一个新的RxList实例,会导致原有的UI监听绑定失效。改用assignAll更新已有RxList的内容,能保证UI正确响应数据变化。
3. 优化回调中的异步保存逻辑
onItemAdded和onItemRemoved回调里调用异步方法是可行的,但要确保saveSelectedChoices正确使用已有的preferences实例,并且加上await保证保存操作完成:
Future<void> saveSelectedChoices() async { print("saving"); // 直接使用成员变量的preferences实例 await preferences.setStringList('selected_choices', choices.toList()); print(choices.toList()); }
4. 修复自定义Chip的删除逻辑
在_customChoice的ChiponDeleted回调里,你直接操作selectedItems是无效的——这个列表是DropdownSearch传递的副本,应该直接操作控制器里的choices并触发保存:
onDeleted: () { // 直接操作控制器的choices列表 controller.choices.remove(e); // 调用保存方法同步到本地存储 controller.saveSelectedChoices(); },
5. 修复FocusNode的内存泄漏问题
你在_buildDropdownSearch里每次build都会创建新的FocusNode,这会导致内存泄漏。把它移到_MyHomePageState的成员变量中,并在页面销毁时清理:
class _MyHomePageState extends State<MyHomePage> { // 将FocusNode定义为组件成员变量 late FocusNode _dropdownFocusNode; final dropdownSearchTheme = ThemeData(...); @override void initState() { super.initState(); _dropdownFocusNode = FocusNode(); // 统一在这里添加监听逻辑 _dropdownFocusNode.addListener(() { final controller = Get.find<QuestionnaireController>(); controller.showBackButton.value = _dropdownFocusNode.hasFocus ? false : true; }); } @override void dispose() { // 销毁FocusNode,避免内存泄漏 _dropdownFocusNode.dispose(); super.dispose(); } // 在_buildDropdownSearch中直接使用这个成员变量 Widget _buildDropdownSearch(...) { final controller = Get.find<QuestionnaireController>(); // 移除这里的FocusNode创建代码 // FocusNode _dropdownFocusNode = FocusNode(); // ... 其他代码 popupProps: PopupPropsMultiSelection.bottomSheet( searchFieldProps: TextFieldProps( // ... focusNode: _dropdownFocusNode, ), // ... ), } }
完成这些修改后,你再测试应用:选中选项后退出再打开,选中项会被预填充;添加/删除选项时数据也会正确保存到本地,不会再出现SharedPreferences查找失败的错误。
备注:内容来源于stack exchange,提问作者Gladiator

