You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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),
      ),
    );
  }
}

关键修复说明

  1. 初始化时机:在initState里调用setupTodo,确保页面加载时就完成prefs实例化,避免late变量未初始化的报错。
  2. 空值安全:判断stringTodo不为空再解码,防止本地无数据时崩溃。
  3. 模型转换:用factory构造函数正确实现JSON和模型的互转,替代原来错误的实例化写法。
  4. 状态优化:先把所有待办项转成模型存到临时列表,再一次性调用setState更新,减少UI重绘次数。
  5. 实例复用:saveTodo直接用已经初始化好的prefs,不用重复调用SharedPreferences.getInstance(),提升效率。

内容的提问来源于stack exchange,提问作者Dishal Kanishka

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.12 13:35:21