Flutter报错:Do not use BuildContexts across async gaps 求解
解决Flutter中“Do not use BuildContexts across async gaps”问题(已尝试mounted判断无效)
我正在学习Angela Yu的Flutter课程(课程内容略显过时),在执行以下异步代码时遇到了**"Do not use BuildContexts across async gaps"**的警告:
void getLocationData() async { Location location = Location(); await location.getCurrentLocation(); NetworkHelper networkHelper = NetworkHelper( 'https://api.openweathermap.org/data/2.5/weather?lat=${location.latitude}&lon=${location.longitude}&appid=$apiKey&units=metric'); var weatherData = await networkHelper.getData(); Navigator.push(context, MaterialPageRoute(builder: (context) { return LocationScreen(locationWeather: weatherData); })); }
我尝试用mounted判断来包裹导航代码,但没有效果:
if (mounted) { Navigator.push(context, MaterialPageRoute(builder: (context) { return LocationScreen(locationWeather: weatherData); })); }
有效解决方案
1. 改用根导航器获取上下文
直接使用context可能因Widget树层级问题导致mounted判断失效,改用根导航器可以规避这个问题:
void getLocationData() async { Location location = Location(); await location.getCurrentLocation(); NetworkHelper networkHelper = NetworkHelper( 'https://api.openweathermap.org/data/2.5/weather?lat=${location.latitude}&lon=${location.longitude}&appid=$apiKey&units=metric'); var weatherData = await networkHelper.getData(); // 获取根导航器实例 final rootNavigator = Navigator.of(context, rootNavigator: true); if (mounted) { rootNavigator.push(MaterialPageRoute(builder: (context) { return LocationScreen(locationWeather: weatherData); })); } }
2. 用addPostFrameCallback延迟导航操作
将导航逻辑放到Widget帧渲染完成后执行,确保Widget状态稳定:
void getLocationData() async { Location location = Location(); await location.getCurrentLocation(); NetworkHelper networkHelper = NetworkHelper( 'https://api.openweathermap.org/data/2.5/weather?lat=${location.latitude}&lon=${location.longitude}&appid=$apiKey&units=metric'); var weatherData = await networkHelper.getData(); WidgetsBinding.instance.addPostFrameCallback((_) { if (mounted) { Navigator.push(context, MaterialPageRoute(builder: (context) { return LocationScreen(locationWeather: weatherData); })); } }); }
3. 用FutureBuilder重构代码(推荐的现代写法)
原课程写法不符合当前Flutter最佳实践,用FutureBuilder可以彻底避免跨异步gap使用context的问题:
// 重构为返回Future的方法 Future<dynamic> fetchLocationData() async { Location location = Location(); await location.getCurrentLocation(); NetworkHelper networkHelper = NetworkHelper( 'https://api.openweathermap.org/data/2.5/weather?lat=${location.latitude}&lon=${location.longitude}&appid=$apiKey&units=metric'); return await networkHelper.getData(); } // 在build方法中使用FutureBuilder @override Widget build(BuildContext context) { return Scaffold( // ...其他页面组件 body: FutureBuilder( future: fetchLocationData(), builder: (context, snapshot) { if (snapshot.connectionState == ConnectionState.done && snapshot.hasData) { return ElevatedButton( onPressed: () { Navigator.push(context, MaterialPageRoute(builder: (context) { return LocationScreen(locationWeather: snapshot.data); })); }, child: const Text('查看天气'), ); } else if (snapshot.connectionState == ConnectionState.waiting) { return const Center(child: CircularProgressIndicator()); } else { return const Center(child: Text('获取数据失败')); } }, ), ); }
4. 确认mounted判断的正确性
如果getLocationData在StatefulWidget的State类中,确保mounted是直接调用State的属性。也可以在异步操作开始前提前记录mounted状态:
void getLocationData() async { // 提前记录当前组件挂载状态 final isMounted = mounted; Location location = Location(); await location.getCurrentLocation(); NetworkHelper networkHelper = NetworkHelper( 'https://api.openweathermap.org/data/2.5/weather?lat=${location.latitude}&lon=${location.longitude}&appid=$apiKey&units=metric'); var weatherData = await networkHelper.getData(); if (isMounted) { Navigator.push(context, MaterialPageRoute(builder: (context) { return LocationScreen(locationWeather: weatherData); })); } }
内容的提问来源于stack exchange,提问作者Nakul Bisht
相关产品推荐
相关产品推荐

