【发布时间】:2019-03-22 13:25:20
【问题描述】:
我正在开发一个显示 SQFlite 表中的列表的程序。快照列表的未来正在被解雇,我无法确定。它的发射次数大约是需要的 3 倍。它需要触发的唯一时间是 (1) 程序第一次激活时,以及 (2) 从可以创建、读取、更新和删除的更新屏幕返回时。因此,我在从该屏幕返回时设置了一个标志,以指示需要刷新快照。然后在选择数据的函数中,检查是否设置了标志,然后才选择表。
现在只是运行程序进行一些添加和删除,导致快照选择如下:
“I/flutter (24769):Fetched = false,Fetch 尝试 = 20,Fetched = 7”
这表示只需要 7 个选择,但请求了 20 个。
有人可以告诉我在不必要时防止 Future 触发的正确方法吗? 相关代码如下:
body: Container(
padding: EdgeInsets.all(16.0),
child: FutureBuilder<List<Map>>(
future: _fetchDataFromDb(),
builder: (context, AsyncSnapshot<List<Map>> snapshot) {
if (snapshot.connectionState == ConnectionState.done) {
if (!snapshot.hasError && snapshot.hasData) {
return ListView.builder(
itemCount: snapshot == null ? 0 : snapshot.data.length,
itemBuilder: (context, index) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
ListTile(
leading: (IconButton /* Edit */ (
color: Colors.blue,
icon: Icon(Icons.edit),
onPressed: () => _showEditScreen(
Crud.eUpdate,
snapshot.data[index]))),
title:
Text(snapshot.data[index]['title']),
subtitle:
Text(snapshot.data[index]['detail']),
onLongPress: () => _showEditScreen(
Crud.eRead, snapshot.data[index]),
trailing: (IconButton(
color: Colors.red,
icon: Icon(Icons.delete),
onPressed: () => _showEditScreen(
Crud.eDelete,
snapshot.data[index])))),
]);
});
}
}
})),
Future<List<Map>> _fetchDataFromDb() async {
bool tfFetched = false;
_iFetchAttempts++;
if (_tfGetData) {
print("Fetching data");
_snapshot = await _dbHelper.getNoteRecs();
tfFetched = true;
_tfGetData = false;
_iFetched++;
setState(() => _iCount = _snapshot.length);
}
print(
"Fetched = $tfFetched, Fetch attempts = $_iFetchAttempts, Fetched = $_iFetched");
return _snapshot;
}
void _showEditScreen(Crud eCrud, data) async {
try {
NoteRec noteRec = data == null
? null
: NoteRec(data['id'], data['title'], data['detail']);
await Navigator.push(
context,
MaterialPageRoute(
builder: (BuildContext context) =>
NoteEntry(g_crud: eCrud, g_noteRec: noteRec)));
_tfGetData = true; // SET FLAG TO INDICATE SELECT IS REQUIRED
} catch (error) {
print("Error on navigation = ${error.toString()}");
}
}
【问题讨论】:
-
你为什么在这里这样做?:
setState(() => _iCount = _snapshot.length);调用setState可能是导致你的FutureBuilder多次构建的原因,因此再次调用_fetchDataFromDb。您的_fetchDataFromDb应该只做一件事,返回数据,在您的FutureBuilder中使用此方法时不更改状态。 -
我需要 setState 来显示项目计数,如果没有它,它会显示不正确的计数。我之前已经删除了它,但我确实想要它,而且我不知道有其他方法可以在小部件中获得正确的计数。我再次将其删除并运行它,Future 仍然存在不必要的触发。即:“I/flutter (28461):Fetched = true,Fetch 尝试 = 21,Fetched = 11”