添加链接
link管理
链接快照平台
  • 输入网页链接,自动生成快照
  • 标签化管理网页链接
时间:2022-11-17 14:36

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中所用的解决方法