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

Flutter开发:如何在Dialog对话框中展示获取到的天气数据

Flutter定位天气Dialog展示问题修复

现存问题

  • 异步时序错误:queryWeather为异步方法,点击按钮后直接同步弹出Dialog,此时定位、天气接口请求尚未完成,Dialog弹出后不属于当前页面Widget树,不会响应页面State的更新,因此永远停留在加载状态无法展示天气数据
  • 缺少权限校验:使用geolocator获取定位前需要校验位置权限是否授予,缺少权限判断会导致定位失败
  • 无异常兜底逻辑:定位请求、天气接口请求均存在失败可能,未做异常捕获会触发未处理异常崩溃

修复方案

将Dialog弹出逻辑整合到异步方法内部,请求前先弹出加载态Dialog,拿到数据后关闭加载Dialog再弹出天气展示Dialog,同时补充权限校验和异常捕获逻辑,修复后完整代码如下:

import 'package:flutter/material.dart';
import 'package:geolocator/geolocator.dart';
import 'package:weather/weather.dart';

enum AppState { NOT_DOWNLOADED, DOWNLOADING, FINISHED_DOWNLOADING }

class MyAppp extends StatefulWidget {
  @override
  _MyApppState createState() => _MyApppState();
}

class _MyApppState extends State<MyAppp> {
  String key = '856822fd8e22db5e1ba48c0e7d69844a';
  late WeatherFactory ws;
  List<Weather> _data = [];
  AppState _state = AppState.NOT_DOWNLOADED;

  @override
  void initState() {
    super.initState();
    ws = WeatherFactory(key);
  }

  Future<void> queryWeather() async {
    FocusScope.of(context).requestFocus(FocusNode());
    // 先弹出加载Dialog
    showDialog(
      context: context,
      barrierDismissible: false,
      builder: (context) => const Center(child: CircularProgressIndicator()),
    );

    try {
      // 权限校验
      LocationPermission permission = await Geolocator.checkPermission();
      if (permission == LocationPermission.denied) {
        permission = await Geolocator.requestPermission();
        if (permission == LocationPermission.denied) {
          throw "位置权限被拒绝,无法获取定位";
        }
      }
      if (permission == LocationPermission.deniedForever) {
        throw "位置权限被永久拒绝,请前往设置开启权限";
      }

      // 获取定位
      var position = await Geolocator.getCurrentPosition(
          desiredAccuracy: LocationAccuracy.high);
      var lat = position.latitude;
      var long = position.longitude;

      // 请求天气数据
      Weather weather = await ws.currentWeatherByLocation(lat, long);
      _data = [weather];
      _state = AppState.FINISHED_DOWNLOADING;

      // 关闭加载Dialog
      if (mounted) Navigator.pop(context);
      // 弹出展示天气的Dialog
      if (mounted) {
        showDialog<String>(
          context: context,
          builder: (BuildContext context) {
            return Center(
              child: Container(
                height: 500,
                width: 320,
                color: Colors.white,
                child: ListView.separated(
                  itemCount: _data.length,
                  itemBuilder: (context, index) {
                    return ListTile(
                      title: Text("温度:${_data[index].temperature?.celsius?.toStringAsFixed(1)}℃\n"
                          "天气:${_data[index].weatherMain}\n"
                          "城市:${_data[index].areaName}"),
                    );
                  },
                  separatorBuilder: (context, index) => const Divider(),
                ),
              ),
            );
          },
        );
      }
    } catch (e) {
      // 关闭加载Dialog
      if (mounted) Navigator.pop(context);
      // 弹出错误提示
      if (mounted) {
        ScaffoldMessenger.of(context).showSnackBar(
          SnackBar(content: Text("请求失败:$e")),
        );
      }
    }
  }

  Widget _buttons() {
    return Row(
      mainAxisAlignment: MainAxisAlignment.center,
      children: <Widget>[
        Container(
          margin: const EdgeInsets.all(5),
          child: TextButton(
            onPressed: queryWeather,
            style: ButtonStyle(
                backgroundColor: MaterialStateProperty.all(Colors.blue)),
            child: const Text(
              'Fetch weather',
              style: TextStyle(color: Colors.white),
            ),
          ),
        ),
      ],
    );
  }

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: const Text('Weather Example App'),
        ),
        body: Column(
          children: <Widget>[
            _buttons(),
            const Text(
              'Output:',
              style: TextStyle(fontSize: 20),
            ),
            const Divider(
              height: 20.0,
              thickness: 2.0,
            ),
          ],
        ),
      ),
    );
  }
}

额外配置注意

  • Android端需要在android/app/src/main/AndroidManifest.xml中添加位置权限声明
  • iOS端需要在ios/Runner/Info.plist中添加位置权限使用描述

内容的提问来源于stack exchange,提问作者Deepak

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.05 15:45:01