Flutter中SharedPreferences初始化及添加late后数据存储失败求助
问题分析与修复方案
核心问题点
SharedPreferences初始化逻辑混乱:类成员prefs未初始化,加late后又在两个方法里重复获取实例,且setupTodo没在页面初始化时调用,导致读写操作依赖的实例可能从未就绪。- 空值处理粗暴:直接用
!强制解包prefs.getString('todo')的返回值,一旦本地无数据就会触发崩溃,后续存储逻辑也无法执行。 - 模型实例化错误:
todo().fromJson(todo)写法完全错误,正确的模型转JSON/JSON转模型逻辑没走对。 - 状态更新效率低:循环里多次调用
setState会导致不必要的UI重绘。
修复后的完整代码
import 'dart:convert'; import 'package:flutter/material.dart'; import 'package:shared_preferences/shared_preferences.dart'; // 先定义正确的Todo模型类(根据你的实际需求调整字段) class Todo { String title; bool isCompleted; Todo({required this.title, required this.isCompleted}); // JSON转模型:用factory构造函数处理 factory Todo.fromJson(Map<String, dynamic> json) { return Todo( title: json['title'], isCompleted: json['isCompleted'], ); } // 模型转JSON:返回Map格式 Map<String, dynamic> toJson() { return { 'title': title, 'isCompleted': isCompleted, }; } } class Body extends StatefulWidget { const Body({Key? key}) : super(key: key); @override State<Body> createState() => _BodyState(); } class _BodyState extends State<Body> { late SharedPreferences prefs; List<Todo> todos = []; @override void initState() { super.initState(); // 页面初始化时就加载本地存储的数据 setupTodo(); } Future<void> setupTodo() async { prefs = await SharedPreferences.getInstance(); String? stringTodo = prefs.getString('todo'); // 处理本地无数据的情况,避免空指针 if (stringTodo != null) { List<dynamic> todoJsonList = jsonDecode(stringTodo); List<Todo> tempTodos = []; // 批量转换模型,再一次性更新状态 for (var json in todoJsonList) { tempTodos.add(Todo.fromJson(json)); } setState(() { todos = tempTodos; }); } } Future<void> saveTodo() async { // 复用已初始化的prefs实例,不用重复获取 List<Map<String, dynamic>> todoJsonList = todos.map((e) => e.toJson()).toList(); await prefs.setString('todo', jsonEncode(todoJsonList)); } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar(title: const Text('Todo 列表')), body: ListView.builder( itemCount: todos.length, itemBuilder: (ctx, index) { return ListTile( title: Text(todos[index].title), trailing: Checkbox( value: todos[index].isCompleted, onChanged: (val) { setState(() { todos[index].isCompleted = val!; }); saveTodo(); // 状态变更后立即保存 }, ), ); }, ), floatingActionButton: FloatingActionButton( onPressed: () { setState(() { todos.add(Todo(title: '新待办', isCompleted: false)); }); saveTodo(); // 添加新待办后保存 }, child: const Icon(Icons.add), ), ); } }
关键修复说明
- 初始化时机:在
initState里调用setupTodo,确保页面加载时就完成prefs实例化,避免late变量未初始化的报错。 - 空值安全:判断
stringTodo不为空再解码,防止本地无数据时崩溃。 - 模型转换:用
factory构造函数正确实现JSON和模型的互转,替代原来错误的实例化写法。 - 状态优化:先把所有待办项转成模型存到临时列表,再一次性调用
setState更新,减少UI重绘次数。 - 实例复用:
saveTodo直接用已经初始化好的prefs,不用重复调用SharedPreferences.getInstance(),提升效率。
内容的提问来源于stack exchange,提问作者Dishal Kanishka
相关产品推荐
相关产品推荐

