Flutter ListView图片加载崩溃及无限滚动分页失效问题求助
修复Flutter中Firebase图片分页加载崩溃问题
原代码核心问题
- 每次调用
initSliderImages都会全量拉取galerytab1集合的所有图片链接,一次性加载过多图片直接导致内存溢出崩溃 - 同时使用
ScrollController的addListener和NotificationListener,造成加载逻辑重复触发 - 没有利用Firestore的分页能力,完全没实现真正的分页加载逻辑
修复后的完整代码
class _CategoryTab1State extends State<CategoryTab1> { List<String> images = []; late ScrollController controller; final scaffoldKey = GlobalKey<ScaffoldState>(); // 分页相关变量 int _pageSize = 6; // 每页加载6张图片,可根据需求调整 DocumentSnapshot? _lastDocument; // 记录最后一条文档,用于分页游标 bool _isLoading = false; // 避免重复发起请求 @override void initState() { super.initState(); controller = ScrollController()..addListener(_scrollListener); _loadInitialImages(); // 加载第一页数据 if (mounted) { context.read<CategoryTab1Bloc>().data.isNotEmpty ? print('data already loaded') : context.read<CategoryTab1Bloc>().getData(mounted, widget.category); } } @override void dispose() { controller.removeListener(_scrollListener); super.dispose(); } void _scrollListener() { // 当滚动到距离底部200px以内时触发加载 if (controller.position.extentAfter < 200 && !_isLoading) { _loadMoreImages(); } } // 加载初始第一页数据 Future<void> _loadInitialImages() async { setState(() => _isLoading = true); try { var query = FirebaseFirestore.instance .collection('galerytab1') .limit(_pageSize); var snapshot = await query.get(); _processSnapshot(snapshot); } catch (e) { print('加载初始图片失败: $e'); } finally { setState(() => _isLoading = false); } } // 加载更多分页数据 Future<void> _loadMoreImages() async { if (_lastDocument == null) return; // 没有更多数据时直接返回 setState(() => _isLoading = true); try { var query = FirebaseFirestore.instance .collection('galerytab1') .startAfterDocument(_lastDocument!) .limit(_pageSize); var snapshot = await query.get(); _processSnapshot(snapshot); } catch (e) { print('加载更多图片失败: $e'); } finally { setState(() => _isLoading = false); } } // 处理Firestore返回的快照,提取图片链接并追加到列表 void _processSnapshot(QuerySnapshot snapshot) { if (snapshot.docs.isEmpty) return; List<String> newImages = snapshot.docs.map((doc) { return doc.data()?['url'] as String; }).toList(); setState(() { images.addAll(newImages); _lastDocument = snapshot.docs.last; // 更新最后一条文档游标 }); } @override Widget build(BuildContext context) { return ListView.builder( controller: controller, key: widget.key, itemCount: images.length + (_isLoading ? 1 : 0), // 加载时多显示一个加载项 itemExtent: 250, itemBuilder: (context, index) { if (index == images.length) { // 加载中的占位widget return Center(child: CircularProgressIndicator()); } return CachedNetworkImage( imageUrl: images[index], fit: BoxFit.cover, key: ValueKey(images[index]), // 可选:添加加载错误占位图 errorWidget: (context, url, error) => Icon(Icons.error), ); }, ); } }
关键修改说明
- 分页核心逻辑:使用Firestore的
limit控制每页加载数量,startAfterDocument基于上次最后一条文档作为游标,实现真正的分页加载,避免一次性拉取全部数据 - 请求防抖:通过
_isLoading状态变量,避免滚动时重复发起请求 - 滚动监听优化:仅保留
ScrollController的监听,设置合理的触发阈值(200px),避免过早或频繁触发加载 - 加载状态提示:在列表末尾添加加载指示器,提升用户体验
- 错误处理:添加try-catch捕获请求异常,避免崩溃
内容的提问来源于stack exchange,提问作者ComaXD EA1
相关产品推荐
相关产品推荐

