Flutter点击TextButton应用挂起,Google地图异步请求异常
问题:点击获取位置按钮后应用挂起,仅提示异步暂停
我是Flutter和Dart初学者,尝试通过$lat和$lng变量获取初始位置,再通过HTTP请求加载Google静态地图展示,但点击TextButton组件后应用出现挂起情况,仅提示发生异步暂停却未指明具体代码行。
以下是我的location_input.dart代码:
import 'dart:convert'; import 'package:flutter/material.dart'; import 'package:location/location.dart'; import 'package:http/http.dart' as http; import 'package:favorite_places/models/place.dart'; class LocationInput extends StatefulWidget { const LocationInput({super.key}); @override State<StatefulWidget> createState() { return _LocationInputState(); } } class _LocationInputState extends State<LocationInput> { PlaceLocation? _pickedLocation; var _isGettingLocation = false; String get locationImage { if (_pickedLocation == null) { return ''; } final lat = _pickedLocation!.latitude; final lng = _pickedLocation!.longitude; return 'https://maps.googleapis.com/maps/api/staticmap?center=$lat,$lng&zoom=16&size=600x300&maptype=roadmap&markers=color:red%7Clabel:A%7C$lat,$lng&key=API_KEY'; } void _getCurrentLocation() async { Location location = Location(); bool serviceEnabled; PermissionStatus permissionGranted; LocationData locationData; serviceEnabled = await location.serviceEnabled(); if (!serviceEnabled) { serviceEnabled = await location.requestService(); if (!serviceEnabled) { return; } } permissionGranted = await location.hasPermission(); if (permissionGranted == PermissionStatus.denied) { permissionGranted = await location.requestPermission(); if (permissionGranted != PermissionStatus.granted) { return; } } setState(() { _isGettingLocation = true; }); locationData = await location.getLocation(); final lat = locationData.latitude; final lng = locationData.longitude; if (lat == null || lng == null) { return; } final url = Uri.parse( 'https://maps.googleapis.com/maps/api/geocode/json?latlng=$lat,$lng&key=API_KEY'); final response = await http.get(url); final resData = json.decode(response.body); final address = resData['results'][0]['formatted_address']; setState(() { _pickedLocation = PlaceLocation( latitude: lat, longitude: lng, address: address, ); _isGettingLocation = false; }); } @override Widget build(BuildContext context) { Widget previewContent = Text( 'No Location Chosen', textAlign: TextAlign.center, style: Theme.of(context) .textTheme .bodyLarge! .copyWith(color: Theme.of(context).colorScheme.onBackground), ); if (_pickedLocation != null) { previewContent = Image.network( locationImage, fit: BoxFit.cover, width: double.infinity, height: double.infinity, ); } if (_isGettingLocation) { previewContent = const CircularProgressIndicator(); } return Column( children: [ Container( alignment: Alignment.center, height: 170, width: double.infinity, decoration: BoxDecoration( border: Border.all( width: 1, color: Theme.of(context).colorScheme.primary.withOpacity(0.2), )), child: previewContent, ), Row( mainAxisAlignment: MainAxisAlignment.spaceEvenly, children: [ TextButton.icon( onPressed: _getCurrentLocation, icon: const Icon(Icons.location_on), label: const Text('Get Location'), ), TextButton.icon( onPressed: () {}, icon: const Icon(Icons.map), label: const Text('Get Map'), ), ], ), ], ); } }
问题分析与修复方案
核心问题
挂起的主要原因是未处理异步操作中的错误:
- Geocode API请求失败(网络问题、密钥无效、无返回结果)时,
resData['results'][0]会触发空指针异常,导致代码卡在异步流程中,且没有错误提示。 - 若获取位置或API请求出错,
_isGettingLocation状态未被重置,加载指示器一直显示,看起来像应用挂起。
具体修复步骤
1. 为异步方法添加错误捕获与状态重置
修改_getCurrentLocation方法,加入try-catch-finally块,确保无论成功失败都能重置状态,并给用户明确反馈:
void _getCurrentLocation() async { Location location = Location(); LocationData? locationData; setState(() { _isGettingLocation = true; }); try { // 检查位置服务 bool serviceEnabled = await location.serviceEnabled(); if (!serviceEnabled) { serviceEnabled = await location.requestService(); if (!serviceEnabled) { if (mounted) { ScaffoldMessenger.of(context).showSnackBar( const SnackBar(content: Text('位置服务未开启')), ); } return; } } // 检查位置权限 PermissionStatus permissionGranted = await location.hasPermission(); if (permissionGranted == PermissionStatus.denied) { permissionGranted = await location.requestPermission(); if (permissionGranted != PermissionStatus.granted) { if (mounted) { ScaffoldMessenger.of(context).showSnackBar( const SnackBar(content: Text('位置权限未授权')), ); } return; } } // 获取位置数据 locationData = await location.getLocation(); final lat = locationData.latitude; final lng = locationData.longitude; if (lat == null || lng == null) { if (mounted) { ScaffoldMessenger.of(context).showSnackBar( const SnackBar(content: Text('无法获取当前位置')), ); } return; } // 调用Geocode API final url = Uri.parse( 'https://maps.googleapis.com/maps/api/geocode/json?latlng=$lat,$lng&key=API_KEY'); final response = await http.get(url); if (response.statusCode != 200) { if (mounted) { ScaffoldMessenger.of(context).showSnackBar( const SnackBar(content: Text('地址解析失败')), ); } return; } final resData = json.decode(response.body); if (resData['results'] == null || resData['results'].isEmpty) { if (mounted) { ScaffoldMessenger.of(context).showSnackBar( const SnackBar(content: Text('未找到对应地址')), ); } return; } final address = resData['results'][0]['formatted_address']; if (mounted) { setState(() { _pickedLocation = PlaceLocation( latitude: lat, longitude: lng, address: address, ); }); } } catch (e) { if (mounted) { ScaffoldMessenger.of(context).showSnackBar( SnackBar(content: Text('获取位置出错:${e.toString()}')), ); } } finally { if (mounted) { setState(() { _isGettingLocation = false; }); } } }
2. 优化静态地图加载的错误处理
给Image.network添加错误占位符,避免图片加载失败导致UI异常:
if (_pickedLocation != null) { previewContent = Image.network( locationImage, fit: BoxFit.cover, width: double.infinity, height: double.infinity, errorBuilder: (context, error, stackTrace) { return const Icon(Icons.error, color: Colors.red); }, ); }
3. 验证API密钥与网络
- 确保Google Cloud控制台已启用Geocoding API和Static Maps API,且API密钥配置了允许的应用(Android/iOS包名、Web域名)。
- 测试设备/模拟器需有正常网络连接,避免请求超时。
内容的提问来源于stack exchange,提问作者Alden Sison Hernandez
相关产品推荐
相关产品推荐

