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

Flutter滑动删除本地存储数据后热重启恢复的问题求助

Flutter 待办应用删除数据不持久化问题修复

问题诊断

  • 删除操作未持久化到本地存储:滑动删除时仅修改了内存中的todoList,但没有将更新后的列表写入SharedPreferences,导致热重启后从本地读取旧数据,已删除项重新出现。
  • setState错误包裹异步逻辑:onDismissed回调中,将async函数直接传入setState,这是错误用法,setState的回调不能是异步函数,会导致状态更新时机异常。
  • omLoadData未处理空数据:当本地无存储数据时,prefs.getStringList("todo_list")返回null,直接使用data!会触发空指针异常。
  • Dismissible的Key存在重复风险:使用todoList[index]作为Key,如果存在相同内容的待办项,会导致Key重复,引发列表渲染错误。

修复方案与代码实现

以下是修复后的完整代码:

import 'package:flutter/material.dart';
import 'package:shared_preferences/shared_preferences.dart';

class Home extends StatefulWidget {
  const Home({key}) : super(key: key);

  @override
  State<Home> createState() => _HomeState();
}

class _HomeState extends State<Home> {
  final myController = TextEditingController();
  bool submit = false;

  Color mainColor = const Color(0xFFEEEFF5);
  Color secColor = const Color(0xFF3A3A3A);
  Color tdBlue = const Color(0xFF5F52EE);

  String temp = "";
  List<String> todoList = [];

  @override
  void initState() {
    super.initState();

    myController.addListener(() {
      setState(() {
        submit = myController.text.isNotEmpty;
      });
    });

    loadData();
  }

  void submitData() async {
    setState(() {
      todoList.add(temp);
      clearText();
    });
    SharedPreferences prefs = await SharedPreferences.getInstance();
    await prefs.setStringList('todo_list', todoList);
  }

  void loadData() async {
    SharedPreferences prefs = await SharedPreferences.getInstance();
    final data = prefs.getStringList("todo_list");
    if (data != null) {
      setState(() {
        todoList.addAll(data);
      });
    }
  }

  Future<void> deleteItem(int index) async {
    setState(() {
      todoList.removeAt(index);
    });
    // 删除后同步更新本地存储
    SharedPreferences prefs = await SharedPreferences.getInstance();
    await prefs.setStringList('todo_list', todoList);
  }

  @override
  void dispose() {
    myController.dispose();
    super.dispose();
  }

  void clearText() {
    myController.clear();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      backgroundColor: mainColor,
      appBar: AppBar(
        elevation: 0.0,
        backgroundColor: secColor,
        title: const Text(
          'ToDo - List',
          style: TextStyle(
              fontSize: 26.5, fontWeight: FontWeight.bold, fontStyle: FontStyle.italic),
        ),
      ),
      body: Column(
        children: [
          Container(
            margin: const EdgeInsets.only(top: 15.0, left: 13.0, right: 8.0),
            child: Row(
              children: [
                Expanded(
                  child: TextField(
                    onChanged: (String value) {
                      temp = value;
                    },
                    controller: myController,
                    decoration: InputDecoration(
                      prefixIcon: const Icon(Icons.notes, color: Colors.orangeAccent),
                      labelText: 'Замітка',
                      hintText: 'Введіть замітку',
                      filled: true,
                      fillColor: Colors.white,
                      border: const OutlineInputBorder(),
                      contentPadding: const EdgeInsets.all(10.0),
                      enabledBorder: OutlineInputBorder(
                        borderRadius: BorderRadius.circular(30.0),
                      ),
                    ),
                  ),
                ),
                const SizedBox(width: 10.0),
                ElevatedButton(
                  style: ElevatedButton.styleFrom(backgroundColor: tdBlue),
                  onPressed: submit ? () => submitData() : null,
                  child: const Text('+', style: TextStyle(fontSize: 35)),
                ),
              ],
            ),
          ),
          Expanded(
            child: Padding(
              padding: const EdgeInsets.only(top: 5.0),
              child: ListView.builder(
                itemCount: todoList.length,
                itemBuilder: (BuildContext context, int index) {
                  return Dismissible(
                    direction: DismissDirection.endToStart,
                    background: const Card(
                      color: Colors.red,
                      child: Icon(Icons.delete_sweep, size: 30, color: Colors.white),
                    ),
                    // 使用唯一Key避免重复
                    key: Key('${todoList[index]}-$index'),
                    onDismissed: (direction) {
                      deleteItem(index);
                    },
                    child: Card(
                      margin: const EdgeInsets.only(top: 8.5, left: 25.0, right: 25.0),
                      shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(25.0)),
                      elevation: 0.0,
                      child: ListTile(
                        title: Text(todoList[index]),
                      ),
                    ),
                  );
                },
              ),
            ),
          ),
        ],
      ),
    );
  }
}

关键修复点说明

  1. 新增deleteItem方法:将删除逻辑与本地存储更新分离,确保删除后立即同步数据到SharedPreferences。
  2. 修正loadData函数:增加空值判断,避免无存储数据时的空指针异常,同时用setState更新UI。
  3. 修改Dismissible的Key:使用'${todoList[index]}-$index'作为唯一标识,避免重复Key导致的渲染问题。
  4. 移除setState中的异步逻辑:将异步操作移到setState之外,保证状态更新和数据持久化的顺序正确。

内容的提问来源于stack exchange,提问作者Назар Марцинко

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.14 20:01:11