[英]How to prevent FutureBuilder to rebuild even its data is unchanged?
I am currently developing a Flutter App which uses a lots of REST APIs to communicate with server side.我目前正在开发一个 Flutter 应用程序,它使用大量 REST API 与服务器端通信。 I am facing some performance issues related to FutureBuilder widget implemented as below:
我面临一些与 FutureBuilder 小部件相关的性能问题,实现如下:
RefreshIndicator(
displacement: 100.0,
onRefresh: _refreshLastEntries,
child: FutureBuilder<List<Entry>> (
future: lastEntriesList,
builder: (context, snapshot) {
if(snapshot.hasError) print(snapshot.error);
if(snapshot.data == null) return Container();
else return ListView.builder(
controller: _controller,
itemCount: snapshot.data.length,
itemBuilder: (context, index) {
return Padding(
padding: const EdgeInsets.all(10.0),
child: EntryCard(entry: snapshot.data[index])
);
},
);
},
),
),
By the way, there are 2 more FutureBuilder implementations with RefreshIndicator in the same page build, and they are wrapped with a PageView.顺便说一句,在同一个页面构建中还有 2 个带有 RefreshIndicator 的 FutureBuilder 实现,它们用 PageView 包装。 The Flutter Performance tab in Android Studio showing avg.
Android Studio 中的 Flutter 性能选项卡显示平均值。 fps of 30 frames/second (sometimes < 30) in debug mode.
调试模式下 30 帧/秒(有时 < 30)的 fps。 It is better in release mode but still below 60 fps that I can notice a laggy animation.
在发布模式下效果更好,但仍低于 60 fps,我可以注意到 animation 滞后。
Well I know the problem (not sure though) is FutureBuilder trying to rebuild as long as the AsyncSnapshot
has data.好吧,我知道问题(虽然不确定)是 FutureBuilder 试图重建,只要
AsyncSnapshot
有数据。 But I couldn't figure out a better implementation of this.但我想不出更好的实现方式。 The refresh function
_refreshLastEntries()
is implemented as:刷新 function
_refreshLastEntries()
实现为:
Future<Null> _refreshLastEntries() async {
setState(() {
lastEntriesList = fetchLastEntries(2);
});
return Future.delayed(Duration(milliseconds: 600));
}
And the fetchLastEntries(int)
is just for the getting the data and map it into some EntryModel class. fetchLastEntries(int)
仅用于获取数据并将 map 放入某个 EntryModel class 中。 I have tried a setting a global value after successfully getting the data and then use it for building the ListView but it did not work.成功获取数据后,我尝试设置一个全局值,然后将其用于构建 ListView,但它不起作用。
I am testing this app with a Xiaomi MI6 with Snapdragon 835 and Adreno 540 if that matters.如果这很重要,我正在使用带有 Snapdragon 835 和 Adreno 540 的小米 MI6 测试这个应用程序。
I will not attach any other code as the whole PageView build code since it is hard to reproduce the same build, thanks!我不会附加任何其他代码作为整个 PageView 构建代码,因为很难重现相同的构建,谢谢!
The FutureBuilder widget is not supposed to rebuild if the future status does not change.如果未来状态没有改变, FutureBuilder小部件不应该重建。 What probably happens in your case is that
在你的情况下可能发生的是
setState(() {
lastEntriesList = fetchLastEntries(2);
});
inside _refreshLastEntries()
causes a rebuild with the uncompleted future which, upon completion, causes another rebuild through the FutureBuilder.在
_refreshLastEntries()
内部导致未完成的未来重建,完成后,通过 FutureBuilder 导致另一个重建。
Since you're using a RefreshIndicator, my opinion is that you don't need a FutureBuilder.由于您使用的是 RefreshIndicator,我认为您不需要 FutureBuilder。 Do the asynchronous work inside
_refreshLastEntries()
and when complete, update a ListView.builder widget.在
_refreshLastEntries()
中执行异步工作,完成后更新 ListView.builder 小部件。 To be clearer:为了更清楚:
//Declare lastEntriesList as a list
List<Entry> lastEntriesList;
Future<void> _refreshLastEntries() async {
return fetchLastEntries(2).then((lastEntries) {
setState(() {
lastEntriesList = lastEntries;
});
});
}
And modify your subtree as follows:并按如下方式修改您的子树:
RefreshIndicator(
displacement: 100.0,
onRefresh: _refreshLastEntries,
child: ListView.builder(
controller: _controller,
itemCount: lastEntriesList.length,
itemBuilder: (context, index) {
return Padding(
padding: const EdgeInsets.all(10.0),
child: EntryCard(entry: lastEntrieslist[index])
);
},
);,
)
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.