Flutter从Firestore加载数据到列表时重复显示最后一条数据问题
嘿,这个问题我太熟了!一眼就看出问题出在哪——你在循环里一直复用同一个widget.challengesInfo对象,导致列表里所有元素都是同一个对象的引用,最后自然全显示成最后一次修改的数据啦。
具体来说,你每次循环只是修改widget.challengesInfo的属性,然后把它添加到allChallenges列表。但列表里存的是对象的引用,不是这个对象的副本。所以不管你加多少次,列表里的所有元素都指向同一个内存地址的对象,最后所有元素都会显示最后一次循环赋值的内容。
解决方法很简单:每次循环都新建一个AllChallengesStorage实例,而不是复用同一个。修改你的challengesToFeed方法:
Future<List<AllChallengesStorage>> challengesToFeed () async { var queryResult = await Firestore.instance.collection("Users") .where("total_challenges", isGreaterThanOrEqualTo: 1) .getDocuments(); // 每次请求前先清空列表,避免重复添加旧数据 allChallenges.clear(); if (queryResult.documents.isNotEmpty){ for (int i=0; i < queryResult.documents.length; ++i){ var userDoc = queryResult.documents[i]; // 提前取出用户名,避免重复读取 var userName = userDoc.data['username']; for (int j=0; j < userDoc.data['total_challenges']; ++j){ // 关键:这里新建一个实例,而不是复用widget.challengesInfo var newChallenge = AllChallengesStorage(); newChallenge.username = userName; newChallenge.name = userDoc.data['challenges'][j]['name']; newChallenge.description = userDoc.data['challenges'][j]['description']; newChallenge.duration = userDoc.data['challenges'][j]['duration']; allChallenges.add(newChallenge); } } } return allChallenges; }
另外还有个小坑要提醒你:你现在在build方法里直接调用challengesToFeed(),这会导致每次组件重建(比如屏幕旋转、父组件刷新)时都重新发起Firestore请求,既浪费带宽又可能出现重复加载的问题。建议把这个Future存在State里,在initState中初始化:
class _FeedState extends State<Feed> { List<AllChallengesStorage> allChallenges = []; // 用late关键字声明,在initState里初始化 late Future<List<AllChallengesStorage>> _challengesFuture; @override void initState() { super.initState(); // 只在组件初始化时请求一次数据 _challengesFuture = challengesToFeed(); } @override Widget build(BuildContext context) { return Scaffold( body: FutureBuilder<List<AllChallengesStorage>>( future: _challengesFuture, // 使用提前初始化的Future builder: (BuildContext context, AsyncSnapshot snapshot) { if (!snapshot.hasData) return Center(child: Text("Loading...")); return ListView.builder( itemCount: snapshot.data.length, itemBuilder: (BuildContext context, int index) { return _cardBuilder(context, snapshot, index); }, ); }, ), ); } }
这样修改后,每个列表项都会对应独立的AllChallengesStorage实例,显示的内容就会正确啦!
内容的提问来源于stack exchange,提问作者Johnny Bravo
相关产品推荐
相关产品推荐

