如何在该Todo App代码中实现Shared Preferences本地存储?
1. 定义 Todo 数据模型
SharedPreferences 仅支持存储基本数据类型,所以需要把 Todo 对象序列化为 JSON 字符串存储。先创建包含序列化/反序列化方法的 Todo 类:
import 'dart:convert'; class Todo { final String id; final String title; bool isCompleted; Todo({ required this.id, required this.title, this.isCompleted = false, }); // 转成 JSON Map Map<String, dynamic> toJson() { return { 'id': id, 'title': title, 'isCompleted': isCompleted, }; } // 从 JSON Map 解析为 Todo 对象 factory Todo.fromJson(Map<String, dynamic> json) { return Todo( id: json['id'], title: json['title'], isCompleted: json['isCompleted'], ); } }
2. 封装存储与读取方法
直接在页面状态类中实现以下方法,也可以单独抽成工具类:
存储 Todo 列表
把 Todo 列表转为 JSON 字符串列表,存入 SharedPreferences:
Future<void> saveTodos(List<Todo> todos) async { final prefs = await SharedPreferences.getInstance(); final List<String> todosJson = todos.map((todo) => jsonEncode(todo.toJson())).toList(); await prefs.setStringList('todos', todosJson); }
读取本地 Todo 列表
从 SharedPreferences 取出字符串列表,解析为 Todo 对象列表:
Future<List<Todo>> loadTodos() async { final prefs = await SharedPreferences.getInstance(); final List<String>? todosJson = prefs.getStringList('todos'); if (todosJson == null || todosJson.isEmpty) { return []; } return todosJson.map((jsonStr) => Todo.fromJson(jsonDecode(jsonStr))).toList(); }
3. 页面集成与数据展示
基于 StatefulWidget 实现页面,初始化时读取本地数据,操作 Todo 后同步更新存储:
import 'package:flutter/material.dart'; import 'package:shared_preferences/shared_preferences.dart'; class TodoPage extends StatefulWidget { const TodoPage({super.key}); @override State<TodoPage> createState() => _TodoPageState(); } class _TodoPageState extends State<TodoPage> { final TextEditingController _titleController = TextEditingController(); late List<Todo> _todos; @override void initState() { super.initState(); // 页面启动时加载本地数据 _loadLocalTodos(); } Future<void> _loadLocalTodos() async { final loadedTodos = await loadTodos(); setState(() { _todos = loadedTodos; }); } // 添加 Todo Future<void> _addTodo() async { if (_titleController.text.trim().isEmpty) return; final newTodo = Todo( id: DateTime.now().millisecondsSinceEpoch.toString(), title: _titleController.text.trim(), ); setState(() { _todos.add(newTodo); }); await saveTodos(_todos); _titleController.clear(); } // 切换完成状态 Future<void> _toggleTodoStatus(int index) async { setState(() { _todos[index].isCompleted = !_todos[index].isCompleted; }); await saveTodos(_todos); } // 删除 Todo Future<void> _deleteTodo(int index) async { setState(() { _todos.removeAt(index); }); await saveTodos(_todos); } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar(title: const Text('Todo List')), body: Column( children: [ Padding( padding: const EdgeInsets.all(8.0), child: Row( children: [ Expanded( child: TextField( controller: _titleController, decoration: const InputDecoration(hintText: '输入 Todo 内容'), ), ), IconButton(onPressed: _addTodo, icon: const Icon(Icons.add)), ], ), ), Expanded( child: _todos.isEmpty ? const Center(child: Text('暂无 Todo')) : ListView.builder( itemCount: _todos.length, itemBuilder: (context, index) { final todo = _todos[index]; return ListTile( leading: Checkbox( value: todo.isCompleted, onChanged: (_) => _toggleTodoStatus(index), ), title: Text( todo.title, style: TextStyle( decoration: todo.isCompleted ? TextDecoration.lineThrough : null, ), ), trailing: IconButton( icon: const Icon(Icons.delete), onPressed: () => _deleteTodo(index), ), ); }, ), ), ], ), ); } @override void dispose() { _titleController.dispose(); super.dispose(); } }
核心注意点
- 每次修改 Todo 列表(添加、切换状态、删除)后,必须调用
saveTodos同步到本地。 - 页面初始化时调用
loadTodos,确保重启应用后数据能被加载展示。 - 记得在文件顶部导入
dart:convert和shared_preferences包。
内容的提问来源于stack exchange,提问作者Aman Singh
相关产品推荐
相关产品推荐

