Flutter热重载或返回页面时ListView列表重复增长问题求解
问题根源
列表重复累加是两个写法错误导致的:
courses被声明为Future<List<String>>类型,你没有在方法内初始化新的列表实例,每次调用getFolders()都会往已存在的旧列表对象上追加数据,页面返回、热重载触发重建时重复执行拉取逻辑,数据自然会越积越多。你猜测的点是对的:不能直接对Future类型对象调用add方法,Future是异步结果的封装,不是实际的列表实例。FutureBuilder的渲染逻辑错误:你直接对courses这个Future对象取length、按下标取值,拿不到实际的列表数据,渲染逻辑本身就不成立。
修复方案
- 把
courses的初始化放到initState生命周期中,不要在build方法里赋值,避免每次重建都重复触发拉取 - 改写
getFolders方法:方法内部新建临时空列表承载拉取到的文件夹名称,不要操作外部的Future对象,拉取完成后直接返回这个临时列表 - 修正
FutureBuilder逻辑:通过snapshot.data获取异步返回的实际列表,所有列表渲染逻辑都基于这个快照返回的数据实现,不要直接操作外部的Future变量
修复后代码参考
class _SemesterState extends State<Semester> { late Future<List<String>> courses; @override void initState() { super.initState(); courses = getFolders(); } Future<List<String>> getFolders() async { // 每次拉取新建空列表,从根源避免数据累加 List<String> folderList = []; final storageRef = FirebaseStorage.instance.ref().child(widget.value); final listResult = await storageRef.listAll(); for (var prefix in listResult.prefixes) { folderList.add(prefix.name); } return folderList; } @override Widget build(BuildContext context) { return Scaffold( backgroundColor: Colors.white, appBar: AppBar( title: const Text("Semester", style: kTitleStyle), backgroundColor: Colors.white, ), body: FutureBuilder<List<String>>( future: courses, builder: (context, snapshot) { if (snapshot.connectionState == ConnectionState.waiting) { return const Center( child: spinkitLines, ); } if (snapshot.hasError) { return Center(child: Text('加载失败: ${snapshot.error}')); } // 从快照中拿到实际渲染用的列表 final courseList = snapshot.data ?? []; return Column( children: [ const SizedBox(height: 20.0), const Center( child: Text( 'Tap to choose course', style: kPlaceholderStyle, ), ), const SizedBox(height: 30.0), Expanded( child: ListView.builder( itemCount: courseList.length, itemBuilder: (context, index) { return Padding( padding: const EdgeInsets.all(8.0), child: GestureDetector( onTap: () { // 点击业务逻辑 }, child: Container( height: 80, decoration: const BoxDecoration( // 原有装饰配置 ), child: Center( child: Padding( padding: const EdgeInsets.all(5.0), child: Text( courseList[index], style: kCardTitleStyle, ), ), ), ), ), ); }), ) ], ); }, ), ); } }
如果后续需要手动刷新列表,单独实现刷新方法,方法内重新调用
getFolders()给courses赋值后调用setState即可,不要修改initState中的初始化逻辑。
内容的提问来源于stack exchange,提问作者Kevinhector
相关产品推荐
相关产品推荐

