这是一个复杂的问题,但我会尽力解释。
我的项目使用了sqflite数据库。该特定页面根据数据库中的数据返回Dismissible小部件列表。这就是我读取数据的方式:
class TasklistState extends State<Tasklist> {
DBProvider dbProvider = new DBProvider();
Future<List<Task>> allTasks;
@override
void initState() {
allTasks = dbProvider.getallTasks();
super.initState();
}
void update(){
setState(() {
allTasks = dbProvider.getallTasks();
});
}
//build
}
Tasklist小部件将返回一个带有FutureBuilder的页面,该页面将使用数据库中的数据构建一个ListView.builder。 ListView生成Dismissible小部件。关闭Dismissible小部件将更新数据库中的一行,并再次读取数据以更新列表。
TasklistState的构建方法
@override
Widget build(BuildContext context) {
return ListView(
physics: const AlwaysScrollableScrollPhysics(),children: <Widget>[
//other widgets such as a title for the list
),FutureBuilder(
future: allTasks,builder: (context,snapshot){
if(snapshot.hasError){
return Text("Data has error.");
} else if (!snapshot.hasData){
return Center(
child: CircularProgressIndicator(),);
} else {
return pendingList(Task.filterByDone(false,Task.filterByDate(Datetime.now,snapshot.data))); //filters the data to match current day
}
},),//other widgets
],);
}
待处理列表
Widget pendingList(List<Task> tasks){
//some code to return a Text widget if "tasks" is empty
return ListView.separated(
separatorBuilder: (context,index){
return Divider(height: 2.0);
},itemCount: tasks.length,physics: const NeverScrollableScrollPhysics(),shrinkWrap: true,itemBuilder: (context,index){
return Dismissible(
//dismissible backgrounds,other non-required parameters
key: Key(UniqueKey().toString()),onDismissed: (direction) async {
Task toRemove = tasks[index]; //save the dismissed task for the upcoming operations
int removeIndex = tasks.indexWhere((task) => task.id == toRemove.id);
tasks.removeAt(removeIndex); //remove the dismissed task
if(direction == DismissDirection.endToStart) {
ratetask(toRemove).then((value) => update()); //ratetask is a function that updates the task,it is removed from the list
}
if(direction == DismissDirection.startToEnd) {
dbProvider.update(/*code to update selected task*/).then((value) => update());
}
},child: ListTile(
//ListTile details
),);
},);
}
这是问题所在(可能是一种错误的解释,我还是很新的):
关闭窗口小部件实际上会将其从列表中删除。用户解雇任务后,将从列表中“视觉上”删除该任务,并调用update()
方法,该方法调用setState()
。调用setState()
会导致FutureBuilder再次生成,但是dbProvider.getallTasks()
调用在FutureBuilder再次生成时尚未完成。因此,FutureBuilder传递旧快照,这将导致ListView使用刚刚被关闭的Task重新构建。这会导致被解雇的ListTile在被解雇后立即出现,这看起来令人毛骨悚然和错误。
我不知道该如何解决。任何帮助将不胜感激。