You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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'),
            ),
          ],
        ),
      ],
    );
  }
}

问题分析与修复方案

核心问题

挂起的主要原因是未处理异步操作中的错误:

  1. Geocode API请求失败(网络问题、密钥无效、无返回结果)时,resData['results'][0]会触发空指针异常,导致代码卡在异步流程中,且没有错误提示。
  2. 若获取位置或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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.17 02:17:37