【发布时间】:2018-12-31 13:59:20
【问题描述】:
我的用例是创建文章的列表视图(每个项目具有相同的外观,可能有大量文章,例如 > 10000)。我试过了 - 带有 ListView.builder 的 ListView:它假定仅在显示项目时呈现项目 - ScrollController:确定何时加载下一个项目(分页) - 然后我使用List来存储使用http从restful API获取的数据,方法是将http中的数据添加到List实例中
这种方法是可以的,但是如果用户继续滚动页面,List 实例的项目会越来越多,它可能会因堆栈溢出错误而崩溃。
如果我不调用 List.addAll(),而是分配从 api 获取的数据,例如:list = data; 我有一个问题,当用户向上滚动时,他/她将无法看到以前的项目。
有没有解决这个问题的好方法?谢谢!
import 'package:flutter/material.dart';
import 'package:app/model.dart';
import 'package:app/components/item.dart';
abstract class PostListPage extends StatefulWidget {
final String head;
DealListPage(this.head);
}
abstract class PostListPageState<T extends PostListPage> extends State<PostListPage> {
final int MAX_PAGE = 2;
DealListPageState(String head) {
this.head = head;
}
final ScrollController scrollController = new ScrollController();
void doInitialize() {
page = 0;
try {
list.clear();
fetchNextPage();
}
catch(e) {
print("Error: " + e.toString());
}
}
@override
void initState() {
super.initState();
this.fetchNextPage();
scrollController.addListener(() {
double maxScroll = scrollController.position.maxScrollExtent;
double currentScroll = scrollController.position.pixels;
double delta = 200.0; // or something else..
if ( maxScroll - currentScroll <= delta) {
fetchNextPage();
}
});
}
@override
void dispose() {
scrollController.dispose();
super.dispose();
}
void mergeNewResult(List<PostListItem> result) {
list.addAll(result);
}
Future fetchNextPage() async {
if (!isLoading && mounted) {
page++;
setState(() {
isLoading = true;
});
final List<PostListItem> result = await doFetchData(page);
setState(() {
if (result != null && result.length > 0) {
mergeNewResult(result);
} else {
//TODO show notification
}
isLoading = false;
});
}
}
Future doFetchData(final int page);
String head;
List<PostListItem> list = new List();
var isLoading = false;
int page = 0;
int pageSize = 20;
final int scrollThreshold = 10;
Widget buildProgressIndicator() {
return new Padding(
padding: const EdgeInsets.all(8.0),
child: new Center(
child: new Opacity(
opacity: isLoading ? 1.0 : 0.0,
child: new CircularProgressIndicator(),
),
),
);
}
@override
Widget build(BuildContext context) {
ListView listView = ListView.builder(
padding: const EdgeInsets.all(16.0),
itemBuilder: (BuildContext context, int index) {
if (index == list.length) {
return buildProgressIndicator();
}
if (index > 0) {
return Column(
children: [Divider(), PostListItem(list[index])]
);
}
return PostListItem(list[index]);
},
controller: scrollController,
itemCount: list.length
);
return Scaffold(
backgroundColor: Colors.white,
appBar: AppBar(
title: Text(head),
actions: <Widget>[
IconButton(
icon: Icon(Icons.search),
onPressed: () {
},
),
// action button
IconButton(
icon: Icon(Icons.more_horiz),
onPressed: () {
},
),
]
),
body: new RefreshIndicator(
onRefresh: handleRefresh,
child: listView
),
);
}
Future<Null> handleRefresh() async {
doInitialize();
return null;
}
}
在我的情况下,当列表长度为 600 时,我开始出现堆栈溢出错误,例如:
I/flutter ( 8842): Another exception was thrown: Stack Overflow
I/flutter ( 8842): Another exception was thrown: Stack Overflow
屏幕:
不知何故,颤振没有显示更多的错误细节。
【问题讨论】:
-
只需在
ListView.builder#itemBuilder中获取分页数据(使用MapCache进行异步数据访问)- 这样您将在滚动ListView时按需请求数据 -
@pskink:谢谢!但是在这种情况下如何设置 itemCount 参数呢?你有一些示例代码吗?我想知道 itemBuilder() 方法实际上是构建项目,但不确定它是否是更改列表的正确位置。
-
您可以指定计数(如果您知道)或从小部件构建器返回 null - 类似于 this
-
堆栈溢出发生在哪里?您可以添加堆栈跟踪吗?我预计会出现某种“内存不足”错误,但不会出现堆栈溢出。
-
@boformer:我附上了屏幕和错误。不知何故,颤动的细节并不多。
标签: flutter