Flutter中使用SharedPreferences保存对象转字符串列表无报错但保存失败问题求助
我帮你梳理了代码里的几个关键问题,这些都是导致保存失效或加载异常的核心原因:
1. 异步保存操作未等待完成
你的save方法里调用了prefs.setStringList和prefs.setInt,但这些都是异步方法(返回Future<bool>),你没有用await等待它们执行完成。加上点击按钮后立刻调用Navigator.pop(context),很可能保存操作还没写完磁盘就被中断了,导致数据根本没存进去。
修复方案:
给所有SharedPreferences的异步操作加上await,并且让save方法返回Future,确保保存完成后再执行后续操作:
class SharedPrefs { int counter = 0; // 修改为Future方法,明确参数类型 Future<void> save(String key, List<String> list) async { SharedPreferences prefs = await SharedPreferences.getInstance(); // 读取counter时也要await异步操作 if (!await prefs.containsKey('counter')) { await prefs.setInt('counter', counter); } else { counter = prefs.getInt('counter')!; } // 循环确保找到未被使用的key,避免重复key导致保存失败 String targetKey; do { targetKey = '$key$counter'; counter++; } while (await prefs.containsKey(targetKey)); // 等待保存操作完成 await prefs.setStringList(targetKey, list); await prefs.setInt('counter', counter); } // ... 其他方法 }
调用save时也建议等待完成(可选但更安全):
onPressed: () async { // 加上async标记 NotePages page = NotePages( type: 'page', pageName: myController.text, createdTime: DateTime.now()); List<String> pageList = [ page.type, page.pageName, page.createdTime.toIso8601String() ]; await prefs.save('page', pageList); // 等待保存完成再跳转 Navigator.pop(context); }
2. 异步加载数据后未更新UI,同步代码提前执行
你在initState里调用了getPages(),但这是异步方法,执行需要时间。你紧接着就循环notePages,这时候notePages还是空的(异步操作还没完成)。而且即使后续数据加载完成,你也没有调用setState()通知Flutter更新UI。
修复方案:
在getPages()中获取数据后调用setState(),并把处理dropDownItemValue的逻辑放在数据加载完成后:
SharedPrefs prefs = SharedPrefs(); List<NotePages> notePages = []; List<String> dropDownItemValue = []; String? selectedValue; getPages() async { notePages = await prefs.loadAllPages(); setState(() { // 通知UI更新数据 dropDownItemValue.clear(); dropDownItemValue.addAll(notePages.map((page) => page.pageName)); dropDownItemValue.addAll(['', 'Add Page']); selectedValue = dropDownItemValue.isNotEmpty ? dropDownItemValue[0] : null; print(dropDownItemValue); }); } @override void initState() { super.initState(); getPages(); // 只触发异步加载,后续逻辑放在setState里 }
3. 加载方法存在空指针异常风险
你的loadAllPages方法会遍历所有SharedPreferences的key,其中包含counter这个int类型的key。当你调用prefs.getStringList('counter')时会返回null,之后访问shared[0]就会抛出空指针异常,导致整个加载流程失败。
修复方案:
过滤掉非page相关的key,并且先判断shared是否有效再处理:
Future<List<NotePages>> loadAllPages() async { SharedPreferences prefs = await SharedPreferences.getInstance(); List<NotePages> pages = []; final keys = prefs.getKeys(); // 过滤掉counter和非page开头的key,减少无效遍历 final pageKeys = keys.where((key) => key.startsWith('page') && key != 'counter'); for (String key in pageKeys) { final shared = prefs.getStringList(key); // 先判断shared是否有效,避免空指针 if (shared != null && shared.length >=3 && shared[0] == 'page') { NotePages page = NotePages( type: shared[0], pageName: shared[1], createdTime: DateTime.parse(shared[2])); pages.add(page); } } return pages; }
4. 额外优化:避免counter初始化混乱
每次实例化SharedPrefs时,counter都会被重置为0,虽然你会从SharedPreferences读取,但可以在类初始化时就加载counter,避免逻辑混乱:
class SharedPrefs { late int counter; // 初始化时加载counter Future<void> init() async { SharedPreferences prefs = await SharedPreferences.getInstance(); counter = prefs.getInt('counter') ?? 0; } Future<void> save(String key, List<String> list) async { SharedPreferences prefs = await SharedPreferences.getInstance(); String targetKey; do { targetKey = '$key$counter'; counter++; } while (await prefs.containsKey(targetKey)); await prefs.setStringList(targetKey, list); await prefs.setInt('counter', counter); } // ... 其他方法 }
然后在使用前先初始化:
SharedPrefs prefs = SharedPrefs(); @override void initState() { super.initState(); prefs.init().then((_) => getPages()); }
按照这些修改后,你的保存和加载逻辑应该就能正常工作了。
内容的提问来源于stack exchange,提问作者can ağlar kırıcı

