firebase - 长列表的 Flutter 应用程序性能问题
问题描述
我有一个颤振应用程序,用户可以在其中将项目添加到存储在 firebase 中的列表中。用户一次最多可以添加 1000 个项目。最初这不是问题,但是随着列表项的增加,应用程序变得越来越慢,直到在列表中大约有 1000 个项目后一次添加多个项目时,由于内存使用,应用程序崩溃 -
线程 #10,名称 = 'io.flutter.1.ui',停止原因 = EXC_RESOURCE RESOURCE_TYPE_MEMORY(限制 = 1450 MB,未使用 = 0x0)
如何改进代码以提高性能。我想保留 Stream 的设置,因为它可以让我动态地过滤列表。这里还有一个信息是 WidgetA 和 WidgetB 也都使用流数据来显示列表中的列表项的数量。
为了便于阅读,我的代码做了一些简化:
主屏类:
Widget content(context) {
double h = MediaQuery.of(context).size.height; //screen height
double w = MediaQuery.of(context).size.width; //screen width
return StreamProvider<List<Activity>>.value(
catchError: (_, __) => null,
value: DatabaseService().activities(widget.uid),
builder: (context, snapshot) {
return SafeArea(
child: Container(
//color: Theme.of(context).backgroundColor, //SkyHookTheme.background,
child: Scaffold(
backgroundColor: Colors.transparent,
body: NotificationListener<ScrollNotification>(
onNotification: _handleScrollNotification,
child: Stack(children: [
ListView(
controller: _scrollController,
children: <Widget>[
Column(
children: <Widget>[
WidgetA(),
WidgetB(),
ActivityList(), //List of User Activities
],
)
],
),
]),
),
),
),
);
});
}
ActivityList 类 Listview 构建:
ListView buildList(List<Activity> acts){
items = ListView.builder(
shrinkWrap: true,
physics: ClampingScrollPhysics(),
scrollDirection: Axis.vertical,
itemCount: len,
itemBuilder: (context, index) {
return ActivityTile(activity: acts[index], number: acts.length - (index));
},
);
return items;
}
任何提示/提示我如何改进这一点将不胜感激。
谢谢!
解决方案
是的,您应该使用分页或延迟加载!对于大多数移动设备来说,一次读取和渲染 1000 个文档的工作量太大。相反,您应该像这样加载您的文档
import 'package:cloud_firestore/cloud_firestore.dart';
Firestore firestore = Firestore.instance
class LongList extends StatefulWidget {
@override _LongListState createState() => _LongListState(); }
class _LongListState extends State<LongList> {
List<DocumentSnapshot> products = []; // stores fetched products
bool isLoading = false; // track if products fetching
bool hasMore = true; // flag for more products available or not
int documentLimit = 10; // documents to be fetched per request
DocumentSnapshot lastDocument; // flag for last document from where next 10 records to be fetched
ScrollController _scrollController = ScrollController(); // listener for listview scrolling
getProducts() async {
if (!hasMore) {
print('No More Products');
return;
}
if (isLoading) {
return;
}
setState(() {
isLoading = true;
});
QuerySnapshot querySnapshot;
if (lastDocument == null) {
querySnapshot = await firestore
.collection('products')
.orderBy('name')
.limit(documentLimit)
.getDocuments();
} else {
querySnapshot = await firestore
.collection('products')
.orderBy('name')
.startAfterDocument(lastDocument)
.limit(documentLimit)
.getDocuments();
print(1);
}
if (querySnapshot.documents.length < documentLimit) {
hasMore = false;
}
lastDocument = querySnapshot.documents[querySnapshot.documents.length - 1];
products.addAll(querySnapshot.documents);
setState(() {
isLoading = false;
});
}
void initState(){
getProducts();
_scrollController.addListener(() {
double maxScroll = _scrollController.position.maxScrollExtent;
double currentScroll = _scrollController.position.pixels;
double delta = MediaQuery.of(context).size.height * 0.20;
if (maxScroll - currentScroll <= delta) {
getProducts();
}
});
_pageManager = PageManager();
super.initState();
}
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Flutter Pagination with Firestore'),
),
body: Column(children: [
Expanded(
child: products.length == 0
? Center(
child: Text('No Data...'),
)
: ListView.builder(
controller: _scrollController,
itemCount: products.length,
itemBuilder: (context, index) {
return ListTile(
contentPadding: EdgeInsets.all(5),
title: Text(products[index]['name']),
subtitle: Text(products[index] ['short_desc']),
);
},
),
),
isLoading
? Container(
width: MediaQuery.of(context).size.width,
padding: EdgeInsets.all(5),
color: Colors.yellowAccent,
child: Text(
'Loading',
textAlign: TextAlign.center,
style: TextStyle(
fontWeight: FontWeight.bold,
),
),
)
: Container()
]),
);
}
}
推荐阅读
- performance - 如何改进有两种情况的haskell代码?
- r - ggplot2 为值和日期/日期时间指定辅助轴
- radio-button - 如何在不改变其外观的情况下禁用面板上的 TRAdioButtons?
- python - 构建一个发送到不和谐的推特监视器
- spring-boot - Maven Sure-Fire - StartupReportConfiguration 的 ClassNotFoundException
- angular - Angular Universal (SSR),带有 Leaflet 和 ngx-leaflet
- c# - 如何在使用输出绑定到服务总线的天蓝色函数中记录错误?
- sql - SQL 不使用连接查找所有销售订单
- python - 如何智能地从单个 .csv 文件导入多个 pandas 数据帧?
- android - [Flutter] url_launcher 包导致的错误(找不到路径)