异步功能完成后颤振 setState()
Posted
技术标签:
【中文标题】异步功能完成后颤振 setState()【英文标题】:Flutter setState() after completion of async function 【发布时间】:2021-06-02 01:39:29 【问题描述】:我创建了一个基于数据库条目的自定义小部件的 ListView.builder。现在我正在尝试添加删除功能。当我单击该按钮时,该条目会相应地从数据库中删除。但是,尽管调用了 setState(),但 ListView 不会更新。我怀疑这可能是由于删除方法是异步的,我怎样才能让应用程序先删除条目然后刷新 ListView?
我的 ListView.builder 的代码是:
ListView.builder(
padding: const EdgeInsets.all(8.0),
itemExtent: 106.0,
itemCount: snapshot.data.length,
itemBuilder: (context, index)
return CustomListItem(
name: transactionsReversed[index].name,
category: transactionsReversed[index].category,
sign: transactionsReversed[index].sign,
amount: transactionsReversed[index].amount,
id: transactionsReversed[index].id,
delete: ()
print('Running delete function on $transactionsReversed[index].id');
setState(()
_remove(transactionsReversed[index].id);
);
);
),
自定义列表项如下所示:
class CustomListItem extends StatelessWidget
const CustomListItem(
this.name, this.category, this.sign, this.amount, this.id, this.delete
);
final String name;
final String category;
final String sign;
final double amount;
final int id;
final Function delete;
@override
Widget build(BuildContext context)
const double radius = 15.0;
return Padding(
padding: const EdgeInsets.symmetric(vertical: 5.0),
child: InkWell(
onTap: ()
Navigator.pushNamed(context, '/category_viewer', arguments:
'category': category
);
,
child: Container(
color: Colors.transparent,
child: Container(
decoration: BoxDecoration(
color: Colors.black,
borderRadius: new BorderRadius.only(
topLeft: const Radius.circular(radius),
topRight: const Radius.circular(radius),
bottomLeft: const Radius.circular(radius),
bottomRight: const Radius.circular(radius),
),
),
child: Row(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
Expanded(
flex: 1,
child: IconButton(
onPressed: delete,
icon: Icon(
Icons.delete_outlined,
color: Colors.red,
size: 40,
),
color: Colors.red
),
),
Expanded(
flex: 3,
child: Padding(
padding: const EdgeInsets.fromLTRB(5.0, 0.0, 0.0, 0.0),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Text(
name,
style: const TextStyle(
fontWeight: FontWeight.w500,
fontSize: 20.0,
color: Colors.white
),
),
const Padding(padding: EdgeInsets.symmetric(vertical: 2.0)),
Text(
category,
style: const TextStyle(
fontSize: 14.0,
color: Colors.white
),
),
],
),
),
),
Padding(
padding: const EdgeInsets.fromLTRB(0, 0, 50, 0),
child: Text(
'$sign$amount.toStringAsFixed(2)€',
style: TextStyle(
fontSize: 25.0,
color: sign == '+' ? Colors.green : Colors.red
),
),
),
],
),
),
),
),
);
最后,remove方法很简单:
_remove(int id) async
DatabaseHelper helper = DatabaseHelper.instance;
await helper.deleteTransaction(id);
【问题讨论】:
我不确定,但也许你可以初始化一个布尔值。然后,如果 bool 为真,则刷新列表视图。它以 false 开头,当您删除条目时,您可以将您的 bool 设置为 true,然后刷新是否有效? 【参考方案1】:试试这个
将 _remove 更改为将来的 void
Future<void> _remove(int id) async
DatabaseHelper helper = DatabaseHelper.instance;
await helper.deleteTransaction(id);
然后改变你的设置状态
setState(()
_remove(transactionsReversed[index].id).then((_)
setState(()
//setstate
);
);
)
);
【讨论】:
非常感谢,成功了。我不得不在内部 setState() 中再次更新我的数据,但这成功了。 我认为不再需要第一个setState
。【参考方案2】:
您的问题似乎与您在调用 delete 时立即调用 setState
的事实有关,这意味着在调用 helper.deleteTransaction(id);
之前立即触发视图重建。我建议您只在您的 async
_remove
方法返回未来后调用 setState
,如下所示:
将Future<void>
类型添加到您的_remove
方法中:
Future<void> _remove(int id) async
DatabaseHelper helper = DatabaseHelper.instance;
await helper.deleteTransaction(id);
请在收到未来通知后致电您的setState
,如下所示:
delete: ()
print('Running delete function on $transactionsReversed[index].id');
setState(()
_remove(transactionsReversed[index].id).then((value) => setState(()));
);
【讨论】:
【参考方案3】:正如其他答案中提到的,问题是由于 setState
在 async
方法 _remove
完成之前运行。
由于_remove
是您的 Widget 类中的私有方法,也许它可以由 setState
负责。
你的_remove
成为:
Future<void> _remove(int id) async
await DatabaseHelper.instance.deleteTransaction(id);
setState(());
您可以将delete
回调简化为:
ListView.builder(
[...]
itemBuilder: (context, index)
return CustomListItem(
[...]
delete: () => _remove(transactionsReversed[index].id),
);
),
【讨论】:
一般来说,空的 setState 是代码异味。 完全同意这一点。我倾向于更进一步,并认为拥有 setState 是一种代码味道。但是根据问题中提供的信息,我不确定采用了哪种状态管理架构(如果有)。以上是关于异步功能完成后颤振 setState()的主要内容,如果未能解决你的问题,请参考以下文章