在构建期间调用 flutter showdialog setState() 或 markNeedsBuild()
flutter showdialog setState() or markNeedsBuild() called during build
我有一个 streambuilder,它读取一个 firestore 数据库,然后根据它做出反应。它当前列出了我的数据库中的一些信息,但是我想为数据库中出现的特定值添加一个弹出屏幕,当我添加一个 showdialog 函数时,它开始给我
════════ Exception caught by widgets library ═══════════════════════════════════════════════════════
setState() or markNeedsBuild() called during build.
错误。我怎样才能解决这个问题?我的代码如下。提前致谢。
//This is the function causing errors.
_showMaterialDialog (String type) {
if(type=="win"){
gameResult = "You Win, Gratz!";
}else if(type=="lose"){
gameResult = "You Lose :(";
}
print("buraya girdi");
print(gameResult);
showDialog(
context: context,
builder: (_) => AlertDialog(
title: Text("Result"),
content: Text(gameResult),
actions: <Widget>[
FlatButton(
child: Text('Close'),
onPressed: () {
//Navigator.of(context).pop();
Navigator.pushNamed(context, HomeScreen.id);
},
)
],
));
}
@override
Widget build(BuildContext context) {
if(_error) {
return Text('error-game', textDirection: TextDirection.ltr);
}
// Show a loader until FlutterFire is initialized
if (!_initialized) {
return Text('Loading', textDirection: TextDirection.ltr);
}
return StreamBuilder<DocumentSnapshot>(
stream: userSnapshot,
builder: (BuildContext context, AsyncSnapshot<DocumentSnapshot> snapshot) {
if (snapshot.hasError) {
return Text('Something went wrong');
}
if (snapshot.connectionState == ConnectionState.waiting) {
return Text("Loading");
}
if(snapshot.hasData){
Map<String, dynamic> userDocument = snapshot.data.data();
print(collectionPath);
print(docPath);
print(snapshot.data);
print(userDocument);
gameResult = userDocument['status'];
//this is place function called
if(gameResult =="win" || gameResult =="lose"){
return _showMaterialDialog(gameResult);
}
kullanicisayilari = userDocument['atilansayi'];
List<dynamic> kullanicisayilariDuz = [];
List<dynamic> rakipsayilariDuz = [];
List<dynamic> sonuclarDuz = [];
for (var numbers in kullanicisayilari){
var splittedNumber = numbers.split('|');
kullanicisayilariDuz.add(splittedNumber[0]);
}
rakipsayilari = userDocument['rakipsallama'];
sonuc = userDocument['sonuc'];
for (var sonuclar in sonuc){
var splittedSonuc = sonuclar.split('|');
sonuclarDuz.add(splittedSonuc[0]);
}
for (var rakipsayi in rakipsayilari){
var splittedRakipSayi = rakipsayi.split('|');
rakipsayilariDuz.add(splittedRakipSayi[0]);
}
print(myNumbers.decimals);
return MaterialApp(
home:Scaffold(
appBar: AppBar(
backgroundColor: Colors.amberAccent,
title: Text('Sayı Avı Oyun Ekranı'),
),
body:Column(
children: <Widget>[
Expanded(
flex: 80,
child: Row(
children: <Widget>[
Expanded(
flex: 40,
child: Column(
children: <Widget>[
for(var numbers in kullanicisayilariDuz)Text(numbers),
]
),
),
Expanded(
flex: 10,
child: Column(
children: <Widget>[
for(var numbers in sonuclarDuz)Text(numbers),
]
),
),
Expanded(
flex: 50,
child: Column(
children: <Widget>[
for(var numbers in rakipsayilariDuz)Text(numbers),
]
),
),
],
),
),
Expanded(
flex:10,
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
showDeleteNumbers(1,'numberimage1'),
showDeleteNumbers(2,'numberimage2'),
showDeleteNumbers(3,'numberimage3'),
showDeleteNumbers(4,'numberimage4'),
Expanded(
child:FlatButton(
onPressed: (){
sendnumber();
},
child: Image.asset('images/send.png'),
),
),
],
),
),
Expanded(
flex: 10,
child: Row(
children: <Widget>[
attachNumber('1','one.png'),
attachNumber('2','two.png'),
attachNumber('3','three.png'),
attachNumber('4','four.png'),
attachNumber('5','five.png'),
attachNumber('6','six.png'),
attachNumber('7','seven.png'),
attachNumber('8','eight.png'),
attachNumber('9','nine.png'),
attachNumber('0','zero.png'),
],
),
),
],
),
),
);
}
},
);
}
}
可能是因为您在 if(snapshot.hasData) 下再次返回 MaterialApp。尝试删除 MaterialApp 并保留 Scaffold 中的代码。
经过一番研究后,我了解到问题的发生是因为函数小部件构建导致了问题,因为已经发生了一个构建事件,所以我将函数设为 asycn,它现在可以正常工作。
代码如下:
_showMaterialDialog(String type) async{
if(type=="win"){
gameResult = "You Win, Gratz!";
}else if(type=="lose"){
gameResult = "You Lose :(";
}
print("buraya girdi");
print(gameResult);
await Future.delayed(Duration(milliseconds: 50));
showDialog (
context: context,
builder: (_) => AlertDialog(
title: Text("Result"),
content: Text(gameResult),
actions: <Widget>[
FlatButton(
child: Text('Close'),
onPressed: () {
Navigator.pushNamed(context, HomeScreen.id);
},
)
],
));
}
如果您不确定小部件是否仍在构建中,您始终可以使用以下解决方案:
SchedulerBinding.instance!.addPostFrameCallback((_) {
//your dialog
});
我有一个 streambuilder,它读取一个 firestore 数据库,然后根据它做出反应。它当前列出了我的数据库中的一些信息,但是我想为数据库中出现的特定值添加一个弹出屏幕,当我添加一个 showdialog 函数时,它开始给我
════════ Exception caught by widgets library ═══════════════════════════════════════════════════════
setState() or markNeedsBuild() called during build.
错误。我怎样才能解决这个问题?我的代码如下。提前致谢。
//This is the function causing errors.
_showMaterialDialog (String type) {
if(type=="win"){
gameResult = "You Win, Gratz!";
}else if(type=="lose"){
gameResult = "You Lose :(";
}
print("buraya girdi");
print(gameResult);
showDialog(
context: context,
builder: (_) => AlertDialog(
title: Text("Result"),
content: Text(gameResult),
actions: <Widget>[
FlatButton(
child: Text('Close'),
onPressed: () {
//Navigator.of(context).pop();
Navigator.pushNamed(context, HomeScreen.id);
},
)
],
));
}
@override
Widget build(BuildContext context) {
if(_error) {
return Text('error-game', textDirection: TextDirection.ltr);
}
// Show a loader until FlutterFire is initialized
if (!_initialized) {
return Text('Loading', textDirection: TextDirection.ltr);
}
return StreamBuilder<DocumentSnapshot>(
stream: userSnapshot,
builder: (BuildContext context, AsyncSnapshot<DocumentSnapshot> snapshot) {
if (snapshot.hasError) {
return Text('Something went wrong');
}
if (snapshot.connectionState == ConnectionState.waiting) {
return Text("Loading");
}
if(snapshot.hasData){
Map<String, dynamic> userDocument = snapshot.data.data();
print(collectionPath);
print(docPath);
print(snapshot.data);
print(userDocument);
gameResult = userDocument['status'];
//this is place function called
if(gameResult =="win" || gameResult =="lose"){
return _showMaterialDialog(gameResult);
}
kullanicisayilari = userDocument['atilansayi'];
List<dynamic> kullanicisayilariDuz = [];
List<dynamic> rakipsayilariDuz = [];
List<dynamic> sonuclarDuz = [];
for (var numbers in kullanicisayilari){
var splittedNumber = numbers.split('|');
kullanicisayilariDuz.add(splittedNumber[0]);
}
rakipsayilari = userDocument['rakipsallama'];
sonuc = userDocument['sonuc'];
for (var sonuclar in sonuc){
var splittedSonuc = sonuclar.split('|');
sonuclarDuz.add(splittedSonuc[0]);
}
for (var rakipsayi in rakipsayilari){
var splittedRakipSayi = rakipsayi.split('|');
rakipsayilariDuz.add(splittedRakipSayi[0]);
}
print(myNumbers.decimals);
return MaterialApp(
home:Scaffold(
appBar: AppBar(
backgroundColor: Colors.amberAccent,
title: Text('Sayı Avı Oyun Ekranı'),
),
body:Column(
children: <Widget>[
Expanded(
flex: 80,
child: Row(
children: <Widget>[
Expanded(
flex: 40,
child: Column(
children: <Widget>[
for(var numbers in kullanicisayilariDuz)Text(numbers),
]
),
),
Expanded(
flex: 10,
child: Column(
children: <Widget>[
for(var numbers in sonuclarDuz)Text(numbers),
]
),
),
Expanded(
flex: 50,
child: Column(
children: <Widget>[
for(var numbers in rakipsayilariDuz)Text(numbers),
]
),
),
],
),
),
Expanded(
flex:10,
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
showDeleteNumbers(1,'numberimage1'),
showDeleteNumbers(2,'numberimage2'),
showDeleteNumbers(3,'numberimage3'),
showDeleteNumbers(4,'numberimage4'),
Expanded(
child:FlatButton(
onPressed: (){
sendnumber();
},
child: Image.asset('images/send.png'),
),
),
],
),
),
Expanded(
flex: 10,
child: Row(
children: <Widget>[
attachNumber('1','one.png'),
attachNumber('2','two.png'),
attachNumber('3','three.png'),
attachNumber('4','four.png'),
attachNumber('5','five.png'),
attachNumber('6','six.png'),
attachNumber('7','seven.png'),
attachNumber('8','eight.png'),
attachNumber('9','nine.png'),
attachNumber('0','zero.png'),
],
),
),
],
),
),
);
}
},
);
}
}
可能是因为您在 if(snapshot.hasData) 下再次返回 MaterialApp。尝试删除 MaterialApp 并保留 Scaffold 中的代码。
经过一番研究后,我了解到问题的发生是因为函数小部件构建导致了问题,因为已经发生了一个构建事件,所以我将函数设为 asycn,它现在可以正常工作。
代码如下:
_showMaterialDialog(String type) async{
if(type=="win"){
gameResult = "You Win, Gratz!";
}else if(type=="lose"){
gameResult = "You Lose :(";
}
print("buraya girdi");
print(gameResult);
await Future.delayed(Duration(milliseconds: 50));
showDialog (
context: context,
builder: (_) => AlertDialog(
title: Text("Result"),
content: Text(gameResult),
actions: <Widget>[
FlatButton(
child: Text('Close'),
onPressed: () {
Navigator.pushNamed(context, HomeScreen.id);
},
)
],
));
}
如果您不确定小部件是否仍在构建中,您始终可以使用以下解决方案:
SchedulerBinding.instance!.addPostFrameCallback((_) {
//your dialog
});