Flutter调用showDialog遇空检查错误:如何传递有效Context?
Flutter调用showDialog时出现Null check空值错误的解决方法
错误信息
[ERROR:flutter/runtime/dart_vm_initializer.cc(41)] Unhandled Exception: Null check operator used on a null value #0 Navigator.of (package:flutter/src/widgets/navigator.dart:2794) #1 showDialog (package:flutter/src/material/dialog.dart:1425) #2 MyAppState.showMessage (package:simple_sensor_test/main.dart:45) #3 MyAppState.build.<anonymous closure> (package:simple_sensor_test/main.dart:30) #4 _InkResponseState.handleTap (package:flutter/src/material/ink_well.dart:1170) #5 GestureRecognizer.invokeCallback (package:flutter/src/gestures/recognizer.dart:351) #6 TapGestureRecognizer.handleTapUp (package:flutter/src/gestures/tap.dart:656) #7 BaseTapGestureRecognizer._checkUp (package:flutter/src/gestures/tap.dart:313) #8 BaseTapGestureRecognizer.handlePrimaryPointer (package:flutter/src/gestures/tap.dart:246) #9 PrimaryPointerGestureRecognizer.handleEvent (package:flutter/src/gestures/recognizer.dart:703) #10 PointerRouter._dispatch (package:flutter/src/g<…>
完整代码
import 'package:flutter/material.dart'; void main() { runApp(MyApp()); } class MyApp extends StatefulWidget { @override MyAppState createState() => MyAppState(); } class MyAppState extends State<MyApp> { @override Widget build(BuildContext context) { return MaterialApp( home: Scaffold( appBar: AppBar( title: const Text('Testing'), ), body: SingleChildScrollView( child: Column( mainAxisAlignment: MainAxisAlignment.center, children: <Widget>[ Row( // need upright vector, new lat, new lon mainAxisAlignment: MainAxisAlignment.spaceEvenly, children: <Widget>[ ElevatedButton( onPressed: () { showMessage("Hello", "world"); }, child: const Text('Calculate'), ), ], ), ], ), ), ), ); } Future<void> showMessage(String title, String message) async { // Ensure the widget is still mounted and context is valid if (mounted) { showDialog( context: context, builder: (context) => const Center( child: Material( color: Colors.transparent, child: Text('Message'), ), ) ); } } }
问题核心
原本认为State对象继承的Context是有效的,但调用Navigator相关函数时出现空值错误,如何向showDialog传递有效的Context?
解决方法
原因分析
你当前使用的context是MyAppState的上下文,而MyApp直接作为runApp的参数,这个上下文不在MaterialApp的导航器树中。showDialog需要的是能找到Navigator的上下文,也就是MaterialApp内部的上下文。
两种修复方案
- 方案1:拆分Widget结构,将MaterialApp移出StatefulWidget
把MaterialApp放在顶层,让StatefulWidget作为它的子组件,这样State拿到的上下文就处于导航器树中:
import 'package:flutter/material.dart'; void main() { runApp(const MaterialApp( home: MyApp(), )); } class MyApp extends StatefulWidget { const MyApp({super.key}); @override MyAppState createState() => MyAppState(); } class MyAppState extends State<MyApp> { @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: const Text('Testing'), ), body: SingleChildScrollView( child: Column( mainAxisAlignment: MainAxisAlignment.center, children: <Widget>[ Row( mainAxisAlignment: MainAxisAlignment.spaceEvenly, children: <Widget>[ ElevatedButton( onPressed: () { showMessage("Hello", "world"); }, child: const Text('Calculate'), ), ], ), ], ), ), ); } Future<void> showMessage(String title, String message) async { if (mounted) { showDialog( context: context, builder: (context) => AlertDialog( title: Text(title), content: Text(message), actions: [ TextButton( onPressed: () => Navigator.pop(context), child: const Text('确定'), ) ], ) ); } } }
- 方案2:给MaterialApp设置GlobalKey,通过key获取导航器上下文
如果不想调整Widget结构,可以给MaterialApp设置全局Key,通过key.currentContext获取有效导航上下文:
import 'package:flutter/material.dart'; void main() { runApp(MyApp()); } class MyApp extends StatefulWidget { @override MyAppState createState() => MyAppState(); } class MyAppState extends State<MyApp> { final GlobalKey<NavigatorState> _navigatorKey = GlobalKey<NavigatorState>(); @override Widget build(BuildContext context) { return MaterialApp( navigatorKey: _navigatorKey, home: Scaffold( appBar: AppBar( title: const Text('Testing'), ), body: SingleChildScrollView( child: Column( mainAxisAlignment: MainAxisAlignment.center, children: <Widget>[ Row( mainAxisAlignment: MainAxisAlignment.spaceEvenly, children: <Widget>[ ElevatedButton( onPressed: () { showMessage("Hello", "world"); }, child: const Text('Calculate'), ), ], ), ], ), ), ), ); } Future<void> showMessage(String title, String message) async { if (mounted) { showDialog( context: _navigatorKey.currentContext!, builder: (context) => AlertDialog( title: Text(title), content: Text(message), actions: [ TextButton( onPressed: () => Navigator.pop(context), child: const Text('确定'), ) ], ) ); } } }
额外优化
原代码中showDialog的builder返回简单Text,建议改成标准AlertDialog组件,既符合Material设计规范,也能正常关闭弹窗。
内容的提问来源于stack exchange,提问作者Graeme Burton
相关产品推荐
相关产品推荐

