当用户单击按钮时,我正在尝试从 Firebase 中删除数据。
await context
线路有问题!
class SecurityOption extends StatelessWidget {//StatelessWidget
const SecurityOption({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return Column(
children: [
Divider(
height: 3,
),
ListTile(
title: Text('security').tr(),
leading: Container(
height: 30,
width: 30,
decoration: BoxDecoration(
color: Colors.red, borderRadius: BorderRadius.circular(5)),
child: Icon(Feather.lock, size: 20, color: Colors.white),
),
trailing: Icon(
Feather.chevron_right,
size: 20,
),
onTap: () => _openDeleteDialog(context),
),
],
);
}
_openDeleteDialog(context) {
return showDialog(
barrierDismissible: true,
context: context,
builder: (context) {
return AlertDialog(
title: Text('Delete data').tr(),
content: Text('Are you sure?').tr(),
actions: [
TextButton(
onPressed: () async {
Navigator.pop(context);
await context //This line is problematic!
.read<SignInBloc>()
.deleteDatafromDatabase()
.then((_) async =>
await context.read<SignInBloc>().userSignout())
.then(
(_) => context.read<SignInBloc>().afterUserSignOut())
.then((_) {
Future.delayed(Duration(seconds: 1)).then((value) =>
nextScreenCloseOthers(context, WelcomePage()));
});
},
child: Text('YES').tr(),
),
TextButton(
onPressed: () {
Navigator.pop(context);
},
child: Text('cancel').tr())
],
);
});
}
}
SignInBloc 类:
class SignInBloc extends ChangeNotifier {
...
...
...
Future deleteDatafromDatabase () async{
FirebaseFirestore _db = FirebaseFirestore.instance;
await _db.collection('x').doc('y').delete();
}
}
当我运行应用程序并单击按钮时,它会删除数据但给出错误。
发生异常。
FlutterError(查找已停用的小部件的祖先是不安全的。在 此时小部件的元素树的状态不再稳定。 要在其 dispose() 方法中安全地引用小部件的祖先,请保存 通过调用来引用祖先 窗口小部件中的 dependentOnInheritedWidgetOfExactType() didChangeDependency() 方法。)
此外,应用程序冻结(未关闭)。点击、滑动等不起作用...
我该如何解决我的问题?
您已正确识别出有问题的代码。 问题是弹出对话框后,对话框的上下文不再存在,但您正在尝试访问它。 最好不要使用对话框构建器提供的上下文,因为它可以随时关闭。即使您将 Navigator.pop 移到末尾,您也会看到
barrierDismissible: true
,因此可以关闭该对话框,并且您将无法访问上下文。
您可以通过以下方式解决此问题:
dialogContext
并使用它来弹出 Navigator.pop(dialogContext)
并使用传递给 context
的 _openDeleteDialog
进行下一步操作。_openDeleteDialog(context) {
return showDialog(
barrierDismissible: true,
context: context,
builder: (dialogContext) { <------- Change this
return AlertDialog(
title: Text('Delete data').tr(),
content: Text('Are you sure?').tr(),
actions: [
TextButton(
onPressed: () async {
Navigator.pop(dialogContext); <----- Use here
await context <--- Keep as is
.read<SignInBloc>()
.deleteDatafromDatabase()
.then((_) async =>
await context.read<SignInBloc>().userSignout())
.then(
(_) => context.read<SignInBloc>().afterUserSignOut())
.then((_) {
Future.delayed(Duration(seconds: 1)).then((value) =>
nextScreenCloseOthers(context, WelcomePage()));
});
},
child: Text('YES').tr(),
),
TextButton(
onPressed: () {
Navigator.pop(context);
},
child: Text('cancel').tr())
],
);
});
}
_openDeleteDialog
并在 Navigator.pop
之后调用它。onTap: () => _openDeleteDialog(context, ()async {
await context
.read<SignInBloc>()
.deleteDatafromDatabase()
.then((_) async =>
await context.read<SignInBloc>().userSignout())
.then(
(_) => context.read<SignInBloc>().afterUserSignOut())
.then((_) {
Future.delayed(Duration(seconds: 1)).then((value) =>
nextScreenCloseOthers(context, WelcomePage()));
});
}
),
_openDeleteDialog(context, VoidCallback onDelete) {
return showDialog(
barrierDismissible: true,
context: context,
builder: (context) {
return AlertDialog(
title: Text('Delete data').tr(),
content: Text('Are you sure?').tr(),
actions: [
TextButton(
onPressed: () {
Navigator.pop(context);
onDelete();
},
child: Text('YES').tr(),
),
TextButton(
onPressed: () {
Navigator.pop(context);
},
child: Text('cancel').tr())
],
);
});
}
当您在
context
方法中使用 showDailog
时,这是 showDailog
的参数,因此当您使用 Navigator.pop(context);
时,context
不再存在,因此要解决此问题,您需要使用通过使用 context
而不是 build
实现的
this.context
方法的
context
像这样
TextButton(
onPressed: () async {
Navigator.pop(context);
await this.context //This line is problematic!
read<SignInBloc>()
.deleteDatafromDatabase()
.then((_) async =>
await this.context.read<SignInBloc>().userSignout())
.then(
(_) => this.context.read<SignInBloc>().afterUserSignOut())
.then((_) {
Future.delayed(Duration(seconds: 1)).then((value) =>
nextScreenCloseOthers(context, WelcomePage()));
},
);
},
child: Text('YES').tr(),
),
我遇到了类似的问题,这就是我解决它的方法,希望有帮助。