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

Flutter中SharedPreferences保存多下拉框值异常问题求助

Flutter SharedPreferences存储下拉框选中值问题解决

问题描述

在Flutter项目中使用SharedPreferences依赖,期望实现以下功能:

  • 首次打开App时,第一个下拉框默认值为howmany,第二个下拉框默认值为which
  • 用户选择其他值并点击“next”按钮后,关闭App并清除后台进程,再次打开时显示用户之前选择的值(例如选择“three”和“4th”后重启App仍显示该值)

目前从SharedPreferences获取到null值,无法实现预期效果。

错误原因分析

查看代码后发现核心问题:

  • 在读取第二个下拉框存储值的方法中,错误将读取结果赋值给了第一个下拉框的变量dropdownValueMembers,而非第二个下拉框的dropdownValueNumber,导致第二个下拉框永远无法加载保存的值
  • 存储键名data、data2语义模糊,易引发混淆
  • 初始化时的异步方法拆分过细,代码冗余

修复后的完整代码

class _FamilyDetailsScreenState extends State<FamilyDetailsScreen> {
  // 第一个下拉框:孩子数量
  String dropdownValueMembers = 'howmany';
  final List<String> memberItems = ['howmany', 'one', 'two', 'three  ', 'four    ', '5 or more'];

  // 第二个下拉框:第几个孩子
  String dropdownValueNumber = 'which';
  final List<String> numberItems = ['which', '1 st', '2 nd', '3 rd  ', '4 th    ', '5 th'];

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

  // 统一加载保存的所有值
  Future<void> _loadSavedValues() async {
    final SharedPreferences prefs = await SharedPreferences.getInstance();
    setState(() {
      // 读取第一个下拉框的值,默认howmany
      dropdownValueMembers = prefs.getString('number_of_children') ?? 'howmany';
      // 读取第二个下拉框的值,默认which
      dropdownValueNumber = prefs.getString('which_child') ?? 'which';
    });
  }

  // 统一保存选中的所有值
  Future<void> _saveSelectedValues() async {
    final SharedPreferences prefs = await SharedPreferences.getInstance();
    await prefs.setString('number_of_children', dropdownValueMembers);
    await prefs.setString('which_child', dropdownValueNumber);
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      backgroundColor: Colors.white,
      resizeToAvoidBottomInset: false,
      body: Container(
        child: SafeArea(
          child: Column(
            children: <Widget>[
              const Text(
                'family details',
                textAlign: TextAlign.center,
                style: TextStyle(
                  color: Colors.black,
                  fontSize: 18.00,
                  fontWeight: FontWeight.w700,
                ),
              ),
              const SizedBox(height: 30),
              Padding(
                padding: const EdgeInsets.only(top: 10, left: 15),
                child: Row(
                  children: <Widget>[
                    const Icon(
                      Icons.brightness_1,
                      color: Colors.black,
                      size: 10.0,
                    ),
                    const Padding(
                      padding: EdgeInsets.only(left: 13),
                      child: Text(
                        "Number of children",
                        style: TextStyle(fontSize: 15, fontWeight: FontWeight.w600),
                      ),
                    ),
                    Padding(
                      padding: const EdgeInsets.only(left: 2),
                      child: Container(
                        height: 25,
                        decoration: BoxDecoration(
                          boxShadow: const <BoxShadow>[
                            BoxShadow(
                                color: Color.fromRGBO(0, 0, 0, 0.37),
                                blurRadius: 5)
                          ],
                          color: Colors.white,
                          borderRadius: BorderRadius.circular(15),
                        ),
                        child: DropdownButton(
                          underline: Container(),
                          borderRadius: BorderRadius.circular(20),
                          value: dropdownValueMembers,
                          icon: const Icon(Icons.keyboard_arrow_down),
                          items: memberItems.map((String item) {
                            return DropdownMenuItem(
                              value: item,
                              child: SizedBox(
                                height: 15,
                                width: 120.0,
                                child: Text(item,
                                    style: const TextStyle(
                                        fontSize: 13.0,
                                        fontWeight: FontWeight.w700),
                                    textAlign: TextAlign.center),
                              ),
                            );
                          }).toList(),
                          onChanged: (String? newValue) {
                            setState(() {
                              dropdownValueMembers = newValue!;
                            });
                          },
                        ),
                      ),
                    ),
                  ],
                ),
              ),
              const SizedBox(height: 25),
              Row(
                children: [
                  Padding(
                    padding: const EdgeInsets.only(left: 20),
                    child: Text('Which child'),
                  ),
                  Padding(
                    padding: const EdgeInsets.only(left: 100, right: 0, top: 20),
                    child: Container(
                      height: 30,
                      decoration: BoxDecoration(
                        boxShadow: const <BoxShadow>[
                          BoxShadow(
                              color: Color.fromRGBO(0, 0, 0, 0.37),
                              blurRadius: 5)
                        ],
                        color: Colors.white,
                        borderRadius: BorderRadius.circular(15),
                      ),
                      child: DropdownButton(
                        underline: Container(),
                        borderRadius: BorderRadius.circular(20),
                        value: dropdownValueNumber,
                        icon: const Icon(Icons.keyboard_arrow_down),
                        items: numberItems.map((String item) {
                          return DropdownMenuItem(
                            value: item,
                            child: SizedBox(
                              height: 17,
                              width: 120.0,
                              child: Text(item,
                                  style: const TextStyle(
                                      fontSize: 13.0,
                                      fontWeight: FontWeight.w700),
                                  textAlign: TextAlign.center),
                            ),
                          );
                        }).toList(),
                        onChanged: (String? newNumber) {
                          setState(() {
                            dropdownValueNumber = newNumber!;
                          });
                        },
                      ),
                    ),
                  ),
                ],
              ),
              const SizedBox(height: 60),
              Padding(
                padding: const EdgeInsets.only(bottom: 0.0, top: 150),
                child: SizedBox(
                  width: 160.0,
                  height: 35.0,
                  child: ElevatedButton(
                      style: ButtonStyle(
                        shape: MaterialStateProperty.all<RoundedRectangleBorder>(
                          RoundedRectangleBorder(
                            borderRadius: BorderRadius.circular(18.0),
                            side: const BorderSide(color: Colors.blueAccent),
                          ),
                        ),
                      ),
                      onPressed: _saveSelectedValues,
                      child: const Text('next')),
                ),
              ),
            ],
          ),
        ),
      ),
    );
  }
}

修复说明

  1. 修正变量赋值错误:将第二个下拉框的存储值正确赋值给dropdownValueNumber,合并加载逻辑为_loadSavedValues,简化初始化流程
  2. 语义化存储键名:将存储键名改为number_of_children和which_child,避免混淆
  3. 优化异步逻辑:合并保存方法为_saveSelectedValues,统一处理两个下拉框的存储操作,代码更简洁
  4. 规范变量命名:将列表变量改为memberItems、numberItems,提升代码可读性

验证步骤

  1. 首次启动App,两个下拉框分别显示默认值howmany和which
  2. 选择自定义值后点击“next”按钮
  3. 关闭App并清除后台进程,重新打开App,下拉框将显示之前选择的值

内容的提问来源于stack exchange,提问作者Dasun Dola

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.15 23:05:30