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

Flutter中使用Shared Preferences本地持久化数据失败问题排查

Flutter Shared Preferences 持久化失效问题修复

问题背景

需求:在Flutter应用中通过Shared Preferences实现本地数据持久化,确保重启应用后数据不会丢失。
问题:已编写Home页(用于添加/管理数据)和Info页(展示数据详情),但使用Shared Preferences保存数据后,重启应用无法获取到之前保存的值。

核心问题分析

  • 生命周期方法错误:Home页的dispose方法被错误嵌套在initState内部,导致初始化逻辑执行异常,无法正确读取本地存储的数据。
  • 数据存储方式错误:当前代码仅单独存储单个商品名称和价格,而非存储整个商品列表,无法在重启后恢复完整的商品数据集合。
  • StatelessWidget误用生命周期:Info页是StatelessWidget,却尝试重写initState方法,该方法仅适用于StatefulWidget,因此无法执行数据读取逻辑。
  • 删除数据未同步本地存储:删除商品时仅移除内存中的列表项,未同步更新Shared Preferences中的数据,导致重启后已删除的数据重新出现。

修复步骤及代码修改

1. 修正Home页的生命周期方法

将dispose方法从initState中移出,作为_MyhomeState的独立方法,并新增列表加载/保存逻辑:

import 'package:flutter/material.dart';
import 'package:list_ex/product.dart';
import 'package:sizer/sizer.dart';
import 'package:list_ex/info.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'dart:convert';

class Myhome extends StatefulWidget {
  const Myhome({Key? key}) : super(key: key);

  @override
  State<Myhome> createState() => _MyhomeState();
}

class _MyhomeState extends State<Myhome> {
  List <Data> productdata = [];
  final myController = TextEditingController();
  TextEditingController productController = TextEditingController();
  TextEditingController prizeController = TextEditingController();
  late SharedPreferences sharedPreferences;

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

  // 独立的资源释放方法
  @override
  void dispose() {
    myController.dispose();
    productController.dispose();
    prizeController.dispose();
    super.dispose();
  }

  // 从本地加载保存的商品列表
  Future<void> _loadSavedProducts() async {
    sharedPreferences = await SharedPreferences.getInstance();
    String? productsJson = sharedPreferences.getString('products');
    if (productsJson != null) {
      List<dynamic> productsList = jsonDecode(productsJson);
      setState(() {
        productdata = productsList.map((item) => Data(item['product'], item['prize'])).toList();
      });
    }
  }

  // 将商品列表保存到本地
  Future<void> _saveProducts() async {
    List<Map<String, dynamic>> productsMap = productdata.map((product) => {
      'product': product.product,
      'prize': product.prize,
    }).toList();
    String productsJson = jsonEncode(productsMap);
    await sharedPreferences.setString('products', productsJson);
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Products', style: TextStyle(fontSize: 30.0)),
        centerTitle: true,
        backgroundColor: Colors.grey[800],
        actions: [
          IconButton(onPressed: () {
            showDialog(context: context, builder: (context) =>
                Dialog(
                  child: SizedBox(
                    height: 200,
                    width: 200,
                    child: Column(
                      children: [
                        TextFormField(
                          decoration: const InputDecoration(
                            filled: true,
                            labelText: 'product',
                            icon: Icon(Icons.star),
                          ),
                          controller: productController,
                          validator: (value){
                            if(value == null || value.isEmpty){
                              return 'Enter product name';
                            }
                            return null;
                          },
                        ),
                        const Divider(height: 20.0, color: Colors.grey),
                        TextFormField(
                          decoration: const InputDecoration(
                            filled: true,
                            labelText: 'price',
                            icon: Icon(Icons.star),
                          ),
                          keyboardType: TextInputType.number,
                          controller: prizeController,
                        ),
                        ElevatedButton(onPressed: () {
                          if (productController.text.isEmpty || prizeController.text.isEmpty){
                            showDialog(context: context, builder: (context) => const AlertDialog(
                              title: Text('Enter Value'),
                            ));
                          } else{
                            setState(() {
                              productdata.add(Data(productController.text, prizeController.text));
                              productController.text = "";
                              prizeController.text = "";
                              Navigator.of(context).pop();
                            });
                            _saveProducts(); // 添加后同步保存
                          }
                        }, child: const Text('Submit')),
                      ],
                    ),
                  ),
                ),
            );
          }, icon: const Icon(Icons.add))
        ],
      ),
      drawer: Drawer(
        child: ListView(
          padding: EdgeInsets.zero,
          children: const <Widget>[
            UserAccountsDrawerHeader(
              decoration: BoxDecoration(color: Colors.black45),
              accountName: Text('Raj'),
              accountEmail: Text('abc123@gmail.com'),
              currentAccountPicture: CircleAvatar(
                backgroundColor: Colors.orange,
                child: Text('R', style: TextStyle(fontSize: 40)),
              ),
            ),
            ListTile(
              leading: Icon(Icons.home),
              title: Text('Home'),
              onTap: () {},
            ),
            ListTile(
              leading: Icon(Icons.contact_mail),
              title: Text('Contact Us'),
              onTap: () {},
            ),
          ],
        ),
      ),
      body: ListView.builder(
          itemCount: productdata.length,
          itemBuilder: (BuildContext context, int index) {
            return Row(
              mainAxisAlignment: MainAxisAlignment.start,
              children: <Widget>[
                Expanded(
                    child: ListTile(
                      tileColor: Colors.cyan,
                      leading: const Icon(Icons.star),
                      trailing: IconButton(onPressed: () {
                        showDialog(context: context, builder: (context) =>
                            AlertDialog(
                              title: const Text('Delete this?'),
                              content: const Text('Are you sure?'),
                              actions: <Widget>[
                                TextButton(onPressed: () {
                                  Navigator.pop(context);
                                }, child: const Text('Cancel')),
                                TextButton(onPressed: () {
                                  setState(() {
                                    productdata.remove(productdata[index]);
                                    Navigator.pop(context);
                                  });
                                  _saveProducts(); // 删除后同步保存
                                }, child: const Text('Delete', style: TextStyle(
                                  color: Colors.black87,
                                  fontSize: 16,
                                ),))
                              ],
                            ));
                      }, icon: const Icon(Icons.delete)),
                      title: Text(productdata[index].product!, style: const TextStyle(
                        fontSize: 22,
                        fontWeight: FontWeight.bold,
                      )),
                      onTap: () {
                        Navigator.of(context).push(MaterialPageRoute(
                            builder: (context) => Info(value: productdata[index])));
                      },
                    )),
              ],
            );
          }),
    );
  }
}

2. 修正Info页的无效逻辑

移除StatelessWidget中无效的initState方法,直接使用传递的参数展示数据:

import 'package:flutter/material.dart';
import 'package:list_ex/product.dart';

class Info extends StatelessWidget {
  final Data value;

  const Info({Key? key, required this.value}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Scaffold(
        appBar: AppBar(
          title: const Text('Product Info'),
          centerTitle: true,
          backgroundColor: Colors.grey[800],
        ),
        body: Center(
          child: Card(
            color: Colors.cyan,
            shape: RoundedRectangleBorder(
                borderRadius: BorderRadius.circular(20.0)),
            child: Column(
              mainAxisSize: MainAxisSize.min,
              children: <Widget>[
                ListTile(
                  title: Text('Product Name: ${value.product!}', style: const TextStyle(fontSize: 20)),
                  subtitle: Text('Price: ${value.prize!}', style: const TextStyle(
                      fontSize: 20,
                      fontWeight: FontWeight.bold
                  )),
                ),
              ],
            ),
          ),
        )
    );
  }
}

3. 确保Data类支持序列化

修改product.dart中的Data类,使其可以转换为JSON格式:

class Data {
  String? product;
  String? prize;

  Data(this.product, this.prize);

  // 从JSON解析Data对象
  Data.fromJson(Map<String, dynamic> json) {
    product = json['product'];
    prize = json['prize'];
  }

  // 将Data对象转换为JSON
  Map<String, dynamic> toJson() {
    final Map<String, dynamic> data = <String, dynamic>{};
    data['product'] = product;
    data['prize'] = prize;
    return data;
  }
}

内容的提问来源于stack exchange,提问作者Raj Kambli

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.10 17:05:20