flutter - 为什么在 ListView Flutter 中滚动时会多次调用 FutureBuilder?
问题描述
我有一个带有子 FutureBuilder 和 ListView.Builder 的 ListView。在 FutureBuilder 中,我有 ListView。现在的问题是,当我滚动 ListView 父级时,为什么 FutureBuilder 会再次重建?
您可以在这里查看我如何重现此问题https://youtu.be/OKjiMOSJmYA
import 'package:flutter/material.dart';
class DebugScreen extends StatefulWidget {
@override
_DebugScreenState createState() => _DebugScreenState();
}
class _DebugScreenState extends State<DebugScreen> {
List<int> numbers = [1, 2, 3, 4, 5, 6, 7];
var futureData;
var futureBuilderHelloWorld;
Future<List<int>> getFutureData() async {
print("getFutureData");
var numbers = [
1,
2,
3,
4,
5,
6,
7,
8,
9,
10,
11,
12,
13,
14,
15,
16,
17,
18,
19,
20,
21,
22,
23,
24,
25,
26,
27,
28,
29,
30,
];
await Future.delayed(Duration(seconds: 3));
return await numbers;
}
@override
void initState() {
futureData = getFutureData();
futureBuilderHelloWorld = FutureBuilder(
future: futureData,
builder: (context, AsyncSnapshot<List<int>> snapshot) {
print("future builder"); // why this is called when scrolling
switch (snapshot.connectionState) {
case ConnectionState.none:
case ConnectionState.waiting:
return Center(
child: CircularProgressIndicator(),
);
default:
if (snapshot.hasError) {
return Text("Error: " + snapshot.error.toString());
} else {
var numbers = snapshot.data;
return Container(
height: 190.0,
child: ListView.builder(
shrinkWrap: true,
itemCount: numbers.length,
itemBuilder: (context, index) {
return Padding(
padding: const EdgeInsets.all(16.0),
child: Text("Hello world ${numbers[index]}"),
);
},
),
);
}
}
},
);
super.initState();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("Debug Mode"),
),
body: ListView(
children: <Widget>[
futureBuilderHelloWorld,
ListView(
shrinkWrap: true,
physics: ClampingScrollPhysics(),
children: List.generate(100, (index) {
return Text("Flutter $index");
}).toList(),
)
],
),
);
}
}
现在在控制台中就像这样
I/flutter (18634): future builder
I/flutter (18634): future builder
I/flutter (18634): future builder
I/flutter (18634): future builder
解决方案
在文档中指出,如果您将来发生更改,构建方法将始终被调用两次:
If the old future has already completed successfully with data as above, changing configuration to a new future results in snapshot pairs of the form:
new AsyncSnapshot<String>.withData(ConnectionState.none, 'data of first future')
new AsyncSnapshot<String>.withData(ConnectionState.waiting, 'data of second future')
In general, the latter will be produced only when the new future is non-null, and the former only when the old future is non-null.
查看文档:https ://api.flutter.dev/flutter/widgets/FutureBuilder-class.html
您的代码应该通过保持呼叫计数器和仅在第二次呼叫中更新列表来适应这一点。
推荐阅读
- python - Django 数据存储 - SQL 还是其他?
- sql - 使用计算列将现有表转换为时态表(用户定义函数)
- sparql - 将同义词库与 SPARQL (MarkLogic) 一起使用
- keycloak - Keycloak ID 令牌不包含“组”信息
- javascript - 我想在我无法控制 RTE 元素的 RTE 组件中附加一个 ng-click
- groovy - 从 Groovy 2.4 升级到 2.5 时由于“无法启动片段包”而解决 OSGi 测试?
- python - Python:Pandas,计算数据框中子字符串出现次数的最快方法
- javascript - 如何为 Ionic v4 自定义项目提供服务
- typescript - 如何在量角器中执行不同条件的测试用例?
- angular - 如何通过单击 ag-grid 中的按钮获取行数据