我正在尝试 运行 两个 await 和一个 navigator.push 在异步函数中,我在 flutter 中遇到了这个错误
I am trying to run two await and a navigator.push in an async function, and i got this error in flutter
错误:
[错误:flutter/lib/ui/ui_dart_state.cc(186)] 未处理的异常:查找已停用的小部件的祖先是不安全的。
E/flutter (6342): 此时widget的元素树状态不再稳定。
E/flutter (6342):要在其 dispose() 方法中安全地引用小部件的祖先,请通过在小部件的 didChangeDependencies() 方法中调用 dependOnInheritedWidgetOfExactType() 来保存对祖先的引用。
E/flutter ( 6342): #0 Element._debugCheckStateIsActiveForAncestorLookup。 (包:flutter/src/widgets/framework.dart:3864:9)
E/flutter(6342):#1 Element._debugCheckStateIsActiveForAncestorLookup(包:flutter/src/widgets/framework.dart:3878:6)
E/flutter(6342):#2Element.findAncestorStateOfType(包:flutter/src/widgets/framework.dart:3926:12)
E/flutter(6342):#3Navigator.of(包:flutter/src/widgets/navigator.dart:2706:40)
E/flutter(6342):#4Navigator.pop(包:flutter/src/widgets/navigator.dart:2592:15)
E/flutter(6342):#5NotificationDialog.checkAvailabilityOfRide(包:drivers_app/Notifications/notificationDialog.dart:240:20)
E/flutter ( 6342):
我的代码片段:
void checkAvailabilityOfRide(context) async {
var rideRequestId = await rideRequestRef.once();
...
var dataSnapShot2 = await newRequestsRef.child(rideRequestId.value).once();
...
Navigator.push(context, MaterialPageRoute(builder: (context)=>
NewRideScreen(rideDetails: rideDetails)));
...
}
更新代码:
Widget build(BuildContext context) {
return Dialog(
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(12.0)),
backgroundColor: Colors.transparent,
elevation: 1.0,
child: Container(
margin: EdgeInsets.all(5.0),
width: double.infinity,
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(5.0),
),
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
SizedBox(height: 30.0),
Image.asset("images/taxi.png", width: 120.0,),
SizedBox(height: 18.0,),
Text("New Ride Request", style: TextStyle(fontFamily: "Brand-Bold", fontSize: 18.0,),),
SizedBox(height: 30.0),
Padding(
padding: EdgeInsets.all(18.0),
child: Column(
children: [
Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Image.asset("images/pickicon.png", height: 16.0, width: 16.0,),
SizedBox(width: 20.0,),
Expanded(
child: Container(child: Text(rideDetails.pickup_address, style: TextStyle(fontSize: 18.0),)),
),
],
),
SizedBox(height: 15.0),
Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Image.asset("images/desticon.png", height: 16.0, width: 16.0,),
SizedBox(width: 20.0,),
Expanded(
child: Container(child: Text(rideDetails.dropOff_address, style: TextStyle(fontSize: 18.0),)),
)
],
),
SizedBox(height: 15.0),
],
),
),
SizedBox(height: 20.0),
Divider(height: 2.0,color: Colors.black, thickness: 2.0,),
SizedBox(height: 8.0),
Padding(
padding: EdgeInsets.all(20.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
FlatButton(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(18.0),
side: BorderSide(color: Colors.red)),
color: Colors.white,
textColor: Colors.red,
padding: EdgeInsets.all(8.0),
onPressed: ()
{
assetsAudioPlayer.stop();
Navigator.pop(context);
},
child: Text(
"Cancel".toUpperCase(),
style: TextStyle(
fontSize: 14.0,
),
),
),
SizedBox(width: 25.0),
RaisedButton(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(18.0),
side: BorderSide(color: Colors.green)),
onPressed: ()
{
assetsAudioPlayer.stop();
checkAvailabilityOfRide0(context);
checkAvailabilityOfRide(context);
},
color: Colors.green,
textColor: Colors.white,
child: Text("Accept".toUpperCase(),
style: TextStyle(fontSize: 14)),
),
],
),
),
SizedBox(height: 10.0),
],
),
),
);
}
Future<void> checkAvailabilityOfRide(context) async {
var rideRequestId = await rideRequestRef.once();
Navigator.push(context);
String theRideId = "";
var dataSnapShot2 = await newRequestsRef.child( rideRequestId.value).once();
/*... process...*/
if(theRideId == rideDetails.ride_request_id && r2canShare) {
rideRequestRef.set("accepted");
AssistantMethods.disableHomeTabLiveLocationUpdates();
Navigator.push(context, MaterialPageRoute(builder: (context) =>
NewRideScreen(rideDetails: rideDetails)));
}
else if(theRideId == 'cancelled') {
displayToastMessage("Ride has been Cancelled.", context);
}
else if(theRideId == 'cancelled') {
displayToastMessage("Ride has been time out.", context);
}
else if(r2canShare == false) {
assetsAudioPlayer.stop();
displayToastMessage("Rider 2 cannot shared ride, out of range.", context);
}
else {
displayToastMessage("Ride not exists.", context);
}
}
修改后的代码:
void checkAvailabilityOfRide(context)async{
var dataSnapShot2 = await newRequestsRef.child( (await
rideRequestRef.once()).value).once();
Navigator.pop(context);
String theRideId = "";
/*... process...*/
@Nin Yu,过去几天我遇到了同样的错误,我尝试使用@Patrick 的回答来修复,但有时效果不佳。当我仔细调试它时,我发现我多次调用包含 Navigator 的方法。所以有时我得到上下文并安全地传递到下一个屏幕,有些它会抛出错误。我会建议调试方法并检查它是否发生。
正如发布者所发现的(参见问题评论),该错误是由于在 Navigator.pop
和 Navigator.push
之间执行异步 await
引起的。我猜 await
让 Flutter 有时间在 push
之前销毁当前屏幕,这会导致 push
.
出现异常
请注意,Flutter 提供了多种同时弹出和推送的方式,这避免了中间代码出现的机会:pushReplacement
和 pushReplacementNamed
将当前屏幕替换为新屏幕,并且popAndPushNamed
对不同的动画做同样的事情。
错误: [错误:flutter/lib/ui/ui_dart_state.cc(186)] 未处理的异常:查找已停用的小部件的祖先是不安全的。 E/flutter (6342): 此时widget的元素树状态不再稳定。 E/flutter (6342):要在其 dispose() 方法中安全地引用小部件的祖先,请通过在小部件的 didChangeDependencies() 方法中调用 dependOnInheritedWidgetOfExactType() 来保存对祖先的引用。 E/flutter ( 6342): #0 Element._debugCheckStateIsActiveForAncestorLookup。 (包:flutter/src/widgets/framework.dart:3864:9) E/flutter(6342):#1 Element._debugCheckStateIsActiveForAncestorLookup(包:flutter/src/widgets/framework.dart:3878:6) E/flutter(6342):#2Element.findAncestorStateOfType(包:flutter/src/widgets/framework.dart:3926:12) E/flutter(6342):#3Navigator.of(包:flutter/src/widgets/navigator.dart:2706:40) E/flutter(6342):#4Navigator.pop(包:flutter/src/widgets/navigator.dart:2592:15) E/flutter(6342):#5NotificationDialog.checkAvailabilityOfRide(包:drivers_app/Notifications/notificationDialog.dart:240:20) E/flutter ( 6342):
我的代码片段:
void checkAvailabilityOfRide(context) async {
var rideRequestId = await rideRequestRef.once();
...
var dataSnapShot2 = await newRequestsRef.child(rideRequestId.value).once();
...
Navigator.push(context, MaterialPageRoute(builder: (context)=>
NewRideScreen(rideDetails: rideDetails)));
...
}
更新代码:
Widget build(BuildContext context) {
return Dialog(
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(12.0)),
backgroundColor: Colors.transparent,
elevation: 1.0,
child: Container(
margin: EdgeInsets.all(5.0),
width: double.infinity,
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(5.0),
),
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
SizedBox(height: 30.0),
Image.asset("images/taxi.png", width: 120.0,),
SizedBox(height: 18.0,),
Text("New Ride Request", style: TextStyle(fontFamily: "Brand-Bold", fontSize: 18.0,),),
SizedBox(height: 30.0),
Padding(
padding: EdgeInsets.all(18.0),
child: Column(
children: [
Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Image.asset("images/pickicon.png", height: 16.0, width: 16.0,),
SizedBox(width: 20.0,),
Expanded(
child: Container(child: Text(rideDetails.pickup_address, style: TextStyle(fontSize: 18.0),)),
),
],
),
SizedBox(height: 15.0),
Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Image.asset("images/desticon.png", height: 16.0, width: 16.0,),
SizedBox(width: 20.0,),
Expanded(
child: Container(child: Text(rideDetails.dropOff_address, style: TextStyle(fontSize: 18.0),)),
)
],
),
SizedBox(height: 15.0),
],
),
),
SizedBox(height: 20.0),
Divider(height: 2.0,color: Colors.black, thickness: 2.0,),
SizedBox(height: 8.0),
Padding(
padding: EdgeInsets.all(20.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
FlatButton(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(18.0),
side: BorderSide(color: Colors.red)),
color: Colors.white,
textColor: Colors.red,
padding: EdgeInsets.all(8.0),
onPressed: ()
{
assetsAudioPlayer.stop();
Navigator.pop(context);
},
child: Text(
"Cancel".toUpperCase(),
style: TextStyle(
fontSize: 14.0,
),
),
),
SizedBox(width: 25.0),
RaisedButton(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(18.0),
side: BorderSide(color: Colors.green)),
onPressed: ()
{
assetsAudioPlayer.stop();
checkAvailabilityOfRide0(context);
checkAvailabilityOfRide(context);
},
color: Colors.green,
textColor: Colors.white,
child: Text("Accept".toUpperCase(),
style: TextStyle(fontSize: 14)),
),
],
),
),
SizedBox(height: 10.0),
],
),
),
);
}
Future<void> checkAvailabilityOfRide(context) async {
var rideRequestId = await rideRequestRef.once();
Navigator.push(context);
String theRideId = "";
var dataSnapShot2 = await newRequestsRef.child( rideRequestId.value).once();
/*... process...*/
if(theRideId == rideDetails.ride_request_id && r2canShare) {
rideRequestRef.set("accepted");
AssistantMethods.disableHomeTabLiveLocationUpdates();
Navigator.push(context, MaterialPageRoute(builder: (context) =>
NewRideScreen(rideDetails: rideDetails)));
}
else if(theRideId == 'cancelled') {
displayToastMessage("Ride has been Cancelled.", context);
}
else if(theRideId == 'cancelled') {
displayToastMessage("Ride has been time out.", context);
}
else if(r2canShare == false) {
assetsAudioPlayer.stop();
displayToastMessage("Rider 2 cannot shared ride, out of range.", context);
}
else {
displayToastMessage("Ride not exists.", context);
}
}
修改后的代码:
void checkAvailabilityOfRide(context)async{
var dataSnapShot2 = await newRequestsRef.child( (await
rideRequestRef.once()).value).once();
Navigator.pop(context);
String theRideId = "";
/*... process...*/
@Nin Yu,过去几天我遇到了同样的错误,我尝试使用@Patrick 的回答来修复,但有时效果不佳。当我仔细调试它时,我发现我多次调用包含 Navigator 的方法。所以有时我得到上下文并安全地传递到下一个屏幕,有些它会抛出错误。我会建议调试方法并检查它是否发生。
正如发布者所发现的(参见问题评论),该错误是由于在 Navigator.pop
和 Navigator.push
之间执行异步 await
引起的。我猜 await
让 Flutter 有时间在 push
之前销毁当前屏幕,这会导致 push
.
请注意,Flutter 提供了多种同时弹出和推送的方式,这避免了中间代码出现的机会:pushReplacement
和 pushReplacementNamed
将当前屏幕替换为新屏幕,并且popAndPushNamed
对不同的动画做同样的事情。