Flutter分页加载更多出现重复数据,求代码问题排查
问题分析与修复方案
嘿,我一眼就看到问题所在了——你的页码递增逻辑确实出了小问题,而且还有几个细节可以优化,让我慢慢给你说:
1. 核心错误:页码自增写法无效
你在_getAllNews方法里写的:
currentPage = currentPage++;
这是典型的自增运算符使用错误!currentPage++是后自增,它的执行逻辑是:先返回当前的currentPage值,再把变量自身加1。所以这行代码相当于把当前的页码值重新赋值给自己,完全没有实现“页码+1”的效果!这就导致每次加载更多时,你请求的都是同一页的数据,自然会出现重复内容。
修复方式:直接改成以下两种写法之一即可:
currentPage++; // 或者 currentPage += 1;
2. 额外问题:重复添加滚动监听器
你在initState中调用handleNext(),而handleNext()里每次执行都会给scrollController添加一个新的滚动监听器。这会导致滚动到底部时,多个监听器同时触发_getAllNews请求,不仅浪费服务器资源,还会加重重复数据的问题。
修复方式:把监听器的初始化直接放到initState里,避免重复添加:
@override void initState() { _getAllNews(currentPage); // 直接在这里添加监听器 scrollController.addListener(() async { if (!isLoading && !hasReachedEnd && scrollController.position.maxScrollExtent == scrollController.position.pixels) { _getAllNews(currentPage); } }); super.initState(); } // 删掉原来的handleNext方法
3. 优化点:避免重复/无效请求
当页面已经在加载数据,或者已经加载到最后一页时,应该禁止再次触发请求。可以在触发_getAllNews前添加判断条件,避免不必要的请求:
scrollController.addListener(() async { // 只有当不在加载、没到最后一页,且滚动到底部时才触发请求 if (!isLoading && !hasReachedEnd && scrollController.position.maxScrollExtent == scrollController.position.pixels) { _getAllNews(currentPage); } });
同时,在_getAllNews里,还要判断返回的数据是否为空,来标记hasReachedEnd:
_getAllNews(page) async { setState(() { isLoading = true; }); var articles = await http.get(Uri.parse( "https://pkbhai.com/myprojects/kids-stories/api/all-stories?page=${page}")); var result = json.decode(articles.body); print(result); // 判断返回的数据是否为空,标记是否到最后一页 if (result['data'].isEmpty) { setState(() { hasReachedEnd = true; isLoading = false; }); return; } List<NewsModel> newNews = []; result['data'].forEach((data) { var news = NewsModel(); news.id = data["id"]; news.articleTitle = data["name"]; newNews.add(news); }); if (mounted) { setState(() { _newsList.addAll(newNews); // 用addAll比循环add更高效 isLoading = false; currentPage++; // 这里修正自增逻辑 }); } }
修正后的完整代码
class Tedd extends StatefulWidget { @override _TeddState createState() => _TeddState(); } class _TeddState extends State<Tedd> { List<NewsModel> _newsList = []; bool isLoading = true; int currentPage = 1; bool hasReachedEnd = false; ScrollController scrollController = ScrollController(); _getAllNews(page) async { setState(() { isLoading = true; }); var articles = await http.get(Uri.parse( "https://pkbhai.com/myprojects/kids-stories/api/all-stories?page=${page}")); var result = json.decode(articles.body); print(result); if (result['data'].isEmpty) { setState(() { hasReachedEnd = true; isLoading = false; }); return; } List<NewsModel> newNews = []; result['data'].forEach((data) { var news = NewsModel(); news.id = data["id"]; news.articleTitle = data["name"]; newNews.add(news); }); if (mounted) { setState(() { _newsList.addAll(newNews); isLoading = false; currentPage++; // 修正后的自增逻辑 }); } } @override void initState() { _getAllNews(currentPage); // 直接添加滚动监听器,避免重复添加 scrollController.addListener(() async { if (!isLoading && !hasReachedEnd && scrollController.position.maxScrollExtent == scrollController.position.pixels) { _getAllNews(currentPage); } }); super.initState(); } @override void dispose() { // 记得销毁控制器,避免内存泄漏 scrollController.dispose(); super.dispose(); } @override Widget build(BuildContext context) { return Scaffold( body: ListView.builder( controller: scrollController, itemCount: _newsList.length + (isLoading ? 1 : 0), itemBuilder: (context, index) { if (index == _newsList.length) { return Center( child: CircularProgressIndicator(), ); } return Container( height: 150, child: Text(_newsList[index].articleTitle!)); }, ), ); } }
内容的提问来源于stack exchange,提问作者Pramod Yadav
相关产品推荐
相关产品推荐

