我有一个应用程序,可以将json对象导出到json文件,并且在导出时,我想显示一个带有圆形进度指示器的警报对话框。但是由于某种原因,没有显示带有进度指示器的警报对话框。
这是我导出json之前应用程序的外观:
以下是用于激活导出部分的代码:
...
child: FlatButton(
onPressed: () async{
//Popping the confirm dialog
Navigator.pop(context);
//Showing the progress dialog
showProcessingDialog();
//Buying some time
_timer = Timer(Duration(seconds: 5), exportData);
//Pops the progress dialog
Navigator.pop(context);
//Shows the finished dialog
showFinishedDialog();
},
child: Text(
"Yes",
...
在此警报按钮中单击“是”后,它应该显示进度对话框,但不显示,而是显示完成的对话框。
赞:
这是进度对话框的代码:
void showProcessingDialog() async{
return showDialog(
barrierDismissible: false,
context: context,
builder: (BuildContext context){
return AlertDialog(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.all(Radius.circular(10.0))),
contentPadding: EdgeInsets.fromLTRB(0.0, 0.0, 0.0, 0.0),
content: Container(
width: 250.0,
height: 100.0,
child: Row(
mainAxisAlignment: MainAxisAlignment.start,
children: [
CircularProgressIndicator(),
Text("Exporting...",
style: TextStyle(
fontFamily: "OpenSans",
color: Color(0xFF5B6978)
)
)
]
)
)
);
}
);
}
这是exportData回调:
void exportData() async{
List<dynamic> _msgList = await _msgStorage._getList;
await _expData._saveList(_msgList);
}
我尝试添加Timer类以将完成的对话框延迟3秒钟显示,但是它不起作用。我可以确认我的json文件已成功导出,但是没有显示Timer的回调(即进度对话框)。
我将不胜感激。
更新:
我根据diegoveloper的答案重写了代码:
onPressed: () async{
Navigator.pop(context);
print("confirm dialog has pop");
print("showing processdialog");
showProcessingDialog();
print("processdialog is being shown.");
print("buying some time");
await Future.delayed(Duration(seconds: 5));
print("done buying some time");
print("exporting begin");
await exportData();
print("exporting done");
Navigator.pop(context);
print("processdialog has pop");
print("showing finished dialog");
showFinishedDialog();
print("finished dialog is being shown.");
},
此时,正在显示过程对话框,但是在打印“导出完成”并执行Navigator.pop(context);
之后,出现了错误,并且过程对话框保留在屏幕中,未弹出。
赞:
I/flutter ( 9767): confirm dialog has pop
I/flutter ( 9767): showing processdialog
I/flutter ( 9767): processdialog is being shown.
I/flutter ( 9767): buying some time
I/flutter ( 9767): done buying some time
I/flutter ( 9767): exporting begin
I/flutter ( 9767): exporting done
E/flutter ( 9767): [ERROR:flutter/shell/common/shell.cc(184)] Dart Error: Unhandled exception:
E/flutter ( 9767): Looking up a deactivated widget's ancestor is unsafe.
E/flutter ( 9767): At this point the state of the widget's element tree is no longer stable. To safely refer to a widget's ancestor in its dispose() method, save a reference to the ancestor by calling inheritFromWidgetOfExactType() in the widget's didChangeDependencies() method.
我将await Future.delayed(Duration(seconds: 5));
注释掉后,效果很好。
我的问题是,为什么在使用Future.delayed
时失败了?
这是完整的错误:
I/flutter ( 9767): confirm dialog has pop
I/flutter ( 9767): showing processingdialog
I/flutter ( 9767): processdialog is being shown.
I/flutter ( 9767): buying some time
I/flutter ( 9767): done buying some time
I/flutter ( 9767): exporting begin
I/flutter ( 9767): exporting done
E/flutter ( 9767): [ERROR:flutter/shell/common/shell.cc(184)] Dart Error: Unhandled exception:
E/flutter ( 9767): Looking up a deactivated widget's ancestor is unsafe.
E/flutter ( 9767): At this point the state of the widget's element tree is no longer stable. To safely refer to a widget's ancestor in its dispose() method, save a reference to the ancestor by calling inheritFromWidgetOfExactType() in the widget's didChangeDependencies() method.
E/flutter ( 9767):
E/flutter ( 9767): #0 Element._debugCheckStateIsActiveForAncestorLookup.<anonymous closure> (package:flutter/src/widgets/framework.dart:3246:9)
E/flutter ( 9767): #1 Element._debugCheckStateIsActiveForAncestorLookup (package:flutter/src/widgets/framework.dart:3255:6)
E/flutter ( 9767): #2 Element.ancestorStateOfType (package:flutter/src/widgets/framework.dart:3303:12)
E/flutter ( 9767): #3 Navigator.of (package:flutter/src/widgets/navigator.dart:1288:19)
E/flutter ( 9767): #4 ChatWindow.showExportedDialog.<anonymous closure>.<anonymous closure> (package:msgdiary/main.dart:368:37)
E/flutter ( 9767): <asynchronous suspension>
E/flutter ( 9767): #5 _InkResponseState._handleTap (package:flutter/src/material/ink_well.dart:507:14)
E/flutter ( 9767): #6 _InkResponseState.build.<anonymous closure> (package:flutter/src/material/ink_well.dart:562:30)
E/flutter ( 9767): #7 GestureRecognizer.invokeCallback (package:flutter/src/gestures/recognizer.dart:102:24)
E/flutter ( 9767): #8 TapGestureRecognizer._checkUp (package:flutter/src/gestures/tap.dart:242:9)
E/flutter ( 9767): #9 TapGestureRecognizer.handlePrimaryPointer (package:flutter/src/gestures/tap.dart:175:7)
E/flutter ( 9767): #10 PrimaryPointerGestureRecognizer.handleEvent (package:flutter/src/gestures/recognizer.dart:315:9)
E/flutter ( 9767): #11 PointerRouter._dispatch (package:flutter/src/gestures/pointer_router.dart:73:12)
E/flutter ( 9767): #12 PointerRouter.route (package:flutter/src/gestures/pointer_router.dart:101:11)
E/flutter ( 9767): #13 _WidgetsFlutterBinding&BindingBase&GestureBinding.handleEvent (package:flutter/src/gestures/binding.dart:180:19)
E/flutter ( 9767): #14 _WidgetsFlutterBinding&BindingBase&GestureBinding.dispatchEvent (package:flutter/src/gestures/binding.dart:158:22)
E/flutter ( 9767): #15 _WidgetsFlutterBinding&BindingBase&GestureBinding._handlePointerEvent (package:flutter/src/gestures/binding.dart:138:7)
E/flutter ( 9767): #16 _WidgetsFlutterBinding&BindingBase&GestureBinding._flushPointerEventQueue (package:flutter/src/gestures/binding.dart:101:7)
E/flutter ( 9767): #17 _WidgetsFlutterBinding&BindingBase&GestureBinding._handlePointerDataPacket (package:flutter/src/gestures/binding.dart:85:7)
E/flutter ( 9767): #18 _invoke1 (dart:ui/hooks.dart:168:13)
E/flutter ( 9767): #19 _dispatchPointerDataPacket (dart:ui/hooks.dart:122:5)
更新:
这是我的错。我需要研究更多有关上下文的信息。看来我在两个对话框中都弹出了相同的上下文。我更改了对话框的名称,它起作用了。
答案 0 :(得分:2)
为什么不将其提取到自定义对话框窗口小部件并动态处理其状态?它更干净,更可自定义,而且还设置了计时器(就像您设置的5秒钟一样),因此这不是一个好习惯,因为您不确定要花多少时间来完成工作。
那么我可以建议例如创建一个具有3种状态的enum DialogState
enum DialogState {
LOADING,
COMPLETED,
DISMISSED,
}
然后创建自己的Dialog小部件,该小部件在构建时会接收其当前状态
class MyDialog extends StatelessWidget {
final DialogState state;
MyDialog({this.state});
@override
Widget build(BuildContext context) {
return state == DialogState.DISMISSED
? Container()
: AlertDialog(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.all(
Radius.circular(10.0),
),
),
content: Container(
width: 250.0,
height: 100.0,
child: state == DialogState.LOADING
? Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
CircularProgressIndicator(),
Padding(
padding: const EdgeInsets.only(left: 10.0),
child: Text(
"Exporting...",
style: TextStyle(
fontFamily: "OpenSans",
color: Color(0xFF5B6978),
),
),
)
],
)
: Center(
child: Text('Data loaded with success'),
),
),
);
}
}
,然后在屏幕上将其插入到所需的任何位置。我更改了exportData
函数以对需要5秒的请求进行虚拟处理。
class MyScreen extends StatefulWidget {
_MyScreenState createState() => _MyScreenState();
}
class _MyScreenState extends State<MyScreen> {
DialogState _dialogState = DialogState.DISMISSED;
void _exportData() {
setState(() => _dialogState = DialogState.LOADING);
Future.delayed(Duration(seconds: 5)).then((_) {
setState(() => _dialogState = DialogState.COMPLETED);
Timer(Duration(seconds: 3), () => setState(() => _dialogState = DialogState.DISMISSED));
});
}
@override
Widget build(BuildContext context) {
return Container(
child: Center(
child: Stack(
alignment: Alignment.center,
children: <Widget>[
RaisedButton(
child: Text('Show dialog'),
onPressed: () => _exportData(),
),
MyDialog(
state: _dialogState,
)
],
),
),
);
}
}
答案 1 :(得分:1)
您可以执行以下操作:
onPressed: () async{
//Popping the confirm dialog
Navigator.pop(context);
//Showing the progress dialog
showProcessingDialog();
//wait 5 seconds : just for testing purposes, you don't need to wait in a real scenario
await Future.delayed(Duration(seconds: 5));
//call export data
await exportData();
//Pops the progress dialog
Navigator.pop(context);
//Shows the finished dialog
await showFinishedDialog();
},