flutter awai后不能使用context问题解析
更新时间:2023-05-25 21:55
awai后不能使用context问题解析 报错:Do not use BuildContexts across async gaps.
理解这个问题需要明白 context和widget的对应关系,context和wididget一对一对应,一个context对应一个widget,不明白可以哔哩哔哩搜索王叔不是秃子中有专门讲解..
问题从以下代码中备注解释
// From SO answer
// https://stackoverflow.com/a/69512692/10476111
import 'dart:async';
import 'package:flutter/material.dart';
class TestPage extends StatelessWidget {
const TestPage({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('Home Page')),
body: Center(
child: ElevatedButton(
child: Text('Open Test Page'),
onPressed: () {
Navigator.of(context).push(
MaterialPageRoute(builder: (_) => TestCon()),
);
},
),
),
);
}
}
class TestCon extends StatefulWidget {
@override
State<TestCon> createState() => _TestConState();
}
class _TestConState extends State<TestCon> {
late final Timer timer;
@override
void initState() {
super.initState();
timer = Timer.periodic(Duration(milliseconds: 500), (timer) {
setState(() {});
});
}
@override
void dispose() {
timer.cancel();
super.dispose();
}
@override
Widget build(BuildContext context) {
final time = DateTime.now().millisecondsSinceEpoch;
return Scaffold(
appBar: AppBar(title: Text('Test Page')),
body: Center(
child: Column(
children: [
Text('Current Time: $time'),
MySafeButton(key: UniqueKey()),
MyDangerousButton(key: UniqueKey()),
],
),
),
);
}
}
class MySafeButton extends StatelessWidget {
const MySafeButton({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return ElevatedButton(
child: Text('Open Dialog Then Pop Safely'),
onPressed: () async {
//当像下面的MyDangerousButton那样不先把(Navigator.of(context)[备注Navigator.of(context)其实就是context对应的widiget])存储时候,
//因为await原因,因为是异步方法,所以await回来后可能context已经被flutter丢弃(initState中的代码传入UniqueKey一直刷新)
//所以会报错旧context已经被丢弃,使用丢弃的context中自然会报错
final navigator = Navigator.of(context);
await showDialog(
context: context,
builder: (_) => AlertDialog( //注意这里的build传入的是_
title: Text('Dialog Title'),
actions: [
TextButton(onPressed: () {
navigator.pop();
//当执行这条语句时,实际上也是在TestCon中查找存在的dialog关闭
//navigator.pop();
//比如再次执行这条语句就是关闭TestCon页面了
}, child: Text("关闭")),
],
),
/* //当我们把上面的(_) =>改为 (context)=> 时
builder:(context)=> AlertDialog(
title: Text('Dialog Title'),
actions: [
TextButton(onPressed: () {
Navigator.of(context).pop();
//这时可以正常关闭弹窗,因为当前context是alertdialog自己的widget对应的context
//不会受上层MySafeButton 丢弃的影响
}, child: Text("关闭")),
],
),
*/
);
navigator.pop();
//注意这里是关闭TestCon页面,flutter从context往上查找最近的navigator关闭
},
);
}
}
class MyDangerousButton extends StatelessWidget {
const MyDangerousButton({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return ElevatedButton(
child: Text('Open Dialog Then Pop Dangerously'),
onPressed: () async {
await showDialog(
context: context,
builder: (_) => AlertDialog(
title: Text('Dialog Title'),
),
);
Navigator.of(context).pop();
//报错 Do not use BuildContexts across async gaps.
//所以我们可以提前把旧context对应的navigator也就是Navigator.of(context)存储起来,
//这样就不会出从旧的context查找navigator的问题,也就是上面mysafeBUtton中所用的解决方法
},
);
}
}
上一篇:Flutter Navigator 2.0 和深度链接 下一篇:传递参数的单例模式