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

Flutter中FutureBuilder结合DropdownButton调用setState报错问题

Flutter问题解决:Dropdown重复值错误与JSON重复加载

问题分析

  1. getJsonData重复调用:FutureBuilder的future参数直接传入getJsonData(),每次Widget rebuild(比如调用setState)都会重新执行该方法,导致JSON重复加载。
  2. DropdownButton重复值错误:Students类未正确实现相等性判断(==和hashCode),DropdownButton无法识别选项的唯一性;或因重复加载导致列表出现重复项,选中时触发校验错误。

解决方案

1. 修复JSON重复加载问题

将Future对象存储在State中,仅在initState中初始化一次,避免每次build重新调用:

class TestPage extends StatefulWidget {
  const TestPage({super.key});
  @override
  State<TestPage> createState() => TestPageState();
}

class TestPageState extends State<TestPage> {
  // 声明Future变量,存储数据加载任务
  late Future<List<Students>> _studentDataFuture;

  @override
  void initState() {
    super.initState();
    // 仅在初始化时执行一次数据加载
    _studentDataFuture = getJsonData();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: ...,
      bottomNavigationBar: ...,
      body: FutureBuilder<List<Students>>(
        // 使用存储的Future,而非直接调用方法
        future: _studentDataFuture,
        builder: (context, snapshot) {
          switch (snapshot.connectionState) {
            case ConnectionState.waiting:
              return const Center(child: Text("加载中..."));
            default:
              if (snapshot.hasError) {
                return Center(child: Text('加载失败: ${snapshot.error}'));
              } else if (snapshot.hasData && snapshot.data!.isNotEmpty) {
                // 将加载完成的数据传递给BuildPage
                return BuildPage(students: snapshot.data!);
              } else {
                return const Center(child: Text('暂无数据'));
              }
          }
        },
      ),
    );
  }
}

2. 修复DropdownButton重复值错误

确保Students类重写==运算符和hashCode,基于唯一标识(如学生ID)判断相等性:

class Students {
  final String id; // 学生唯一标识
  final String name;
  // 其他字段

  Students({required this.id, required this.name});

  factory Students.fromJson(Map<String, dynamic> json) {
    return Students(
      id: json['id'],
      name: json['name'],
      // 解析其他字段
    );
  }

  // 重写==运算符,基于id判断相等
  @override
  bool operator ==(Object other) =>
      identical(this, other) ||
      other is Students &&
          runtimeType == other.runtimeType &&
          id == other.id;

  // 重写hashCode,基于id生成
  @override
  int get hashCode => id.hashCode;
}

3. 优化BuildPage的DropdownButton体验

在BuildPage中,根据数据状态控制Dropdown的可用性,避免真机加载延迟导致的交互问题:

class BuildPage extends StatefulWidget {
  final List<Students> students;
  const BuildPage({super.key, required this.students});

  @override
  State<BuildPage> createState() => _BuildPageState();
}

class _BuildPageState extends State<BuildPage> {
  Students? selectedStudent;
  final TextEditingController _textController = TextEditingController();

  @override
  Widget build(BuildContext context) {
    return Column(
      children: [
        DropdownButton<Students>(
          value: selectedStudent,
          // 数据为空时禁用Dropdown
          enabled: widget.students.isNotEmpty,
          items: widget.students.map((student) {
            return DropdownMenuItem<Students>(
              value: student,
              child: Text(student.name),
            );
          }).toList(),
          onChanged: (Students? newValue) {
            setState(() {
              selectedStudent = newValue;
              // 更新文本控制器内容
              _textController.text = newValue?.name ?? '';
            });
          },
        ),
        TextField(controller: _textController),
      ],
    );
  }
}

关键说明

  • 存储Future到State变量:保证数据仅加载一次,避免rebuild时重复执行异步任务。
  • 重写相等性方法:让DropdownButton能正确识别每个选项的唯一性,解决选中时的重复值校验错误。
  • 控制Dropdown可用性:在数据加载完成前禁用控件,避免用户操作空列表,同时提升真机交互体验。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.14 05:30:07