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

Flutter天气应用:如何将GetWeatherModel的JSON数据展示到界面

解决Flutter天气应用中API数据无法展示到界面的问题

核心问题分析

你的代码已经能成功获取天气数据,但无法展示到UI的原因是:

  • 没有将获取到的JSON数据与页面状态(State)绑定
  • 调用异步API时未正确处理Future,导致数据获取后未触发UI更新
  • 使用dynamic类型处理数据,不利于后续UI取值和类型安全

解决方案步骤

1. 创建强类型Weather数据模型

将JSON数据解析为具体Dart类,避免使用dynamic,提升代码可读性与安全性:

class Weather {
  final double temperature;
  final String description;
  final String cityName;
  final int conditionId;

  Weather({
    required this.temperature,
    required this.description,
    required this.cityName,
    required this.conditionId,
  });

  // 从JSON解析为Weather对象
  factory Weather.fromJson(Map<String, dynamic> json) {
    return Weather(
      temperature: json['main']['temp']?.toDouble() ?? 0.0,
      description: json['weather'][0]['description'] ?? 'Unknown',
      cityName: json['name'] ?? 'Unknown City',
      conditionId: json['weather'][0]['id'] ?? 0,
    );
  }
}

2. 修改GetWeatherModel返回Weather模型

更新getLocationWeather方法,返回Future<Weather?>并直接解析为Weather对象:

class GetWeatherModel {
  Future<Weather?> getLocationWeather() async {
    Location location = Location();
    await location.getCurrentLocation();

    // 检查位置是否获取成功
    if (location.latitude == null || location.longitude == null) {
      print('无法获取位置信息');
      return null;
    }

    http.Response response = await http.get(
      Uri.parse(
        "$openWeatherMapURL?lat=${location.latitude}&lon=${location.longitude}&appid=$apiKey&units=metric",
      ),
    );

    if (response.statusCode == 200) {
      var decodedData = jsonDecode(response.body);
      return Weather.fromJson(decodedData);
    } else {
      print('请求失败,状态码:${response.statusCode}');
      return null;
    }
  }
}

3. 页面State绑定数据并处理异步更新

在_WeatherPageState中添加状态变量存储天气数据,修改API调用逻辑,确保数据获取后触发UI更新:

class _WeatherPageState extends State<WeatherPage> {
  GetWeatherModel getWeatherModel = GetWeatherModel();
  Weather? _currentWeather;
 </think_never_used_51bce0c785ca2f68081bfa7d91973934>
```dart
import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
import 'package:geolocator/geolocator.dart';
import 'dart:convert';

//Create some const's for the API key and the openweather url. If i put this in
//the weather class it needs to be static, why is this?
const openWeatherMapURL = 'https://api.openweathermap.org/data/2.5/weather';
const apiKey = '9afee6d05ce90e00ea3e3372128de9b6';

class WeatherPage extends StatefulWidget {
  const WeatherPage({super.key, this.locationWeather});

  final locationWeather;

  @override
  State<WeatherPage> createState() => _WeatherPageState();
}

class _WeatherPageState extends State<WeatherPage> {
  GetWeatherModel getWeatherModel = GetWeatherModel();

  @override
  void initState() {
    // TODO: implement initState
    super.initState();
    getWeatherModel.getLocationWeather();
  }

  Widget build(BuildContext context) {
    return Scaffold(
        appBar: AppBar(
          title: Text('My first weather app'),
        ),
        body: Center(
          child: Column(
            mainAxisAlignment: MainAxisAlignment.center,
            children: [
              Text('stuff'),
              Text(
                'Temperature',
              ),
              Text(
                'Description',
              ),
              ElevatedButton(
                  onPressed: () {
                    setState(() {
                      GetWeatherModel getWeather = GetWeatherModel();
                      getWeather.getLocationWeather();
                    });
                  },
                  child: Text('Get Data'))
            ],
          ),
        ));
  }
}

class Location {
  //Create two variables to store the longitude and latitude retrieved
  //from geo locator
  double? latitude;
  double? longitude;

  //Create a function to retrieve the longitude and latitude from geolocator
  Future<void> getCurrentLocation() async {
    //Get the user permission to use location
    await Geolocator.requestPermission();
    try {
      //try to get the current location from the phone through the
      //geolocator package with low accuracy to save battery and it is just
      //the general area needed
      Position position = await Geolocator.getCurrentPosition(
          desiredAccuracy: LocationAccuracy.low);

      //put the latitude and longitude of the current position into these variabls

      latitude = position.latitude;
      longitude = position.longitude;
    } catch (e) {
      print(e);
      //throw ('Location cannot be found');
    }
  }
}

class GetWeatherModel {
  //Create a function that uses the getCurrentLocation function and uses
//it to retrieve data from the open weather api
  Future<dynamic> getLocationWeather() async {
    Location location = Location();
    await location.getCurrentLocation();
    // print(location.longitude);
    // print(location.latitude);
    http.Response response = await http.get(
      Uri.parse(
        "$openWeatherMapURL?lat=${location.latitude}&lon=${location.longitude}&appid=$apiKey&units=metric",
      ),
    );
    if (response.statusCode == 200) {
      String data = response.body;

      // The decodedData variable needs to be a var because it is a dynamic data type,
      // and we wont know what the type is until it is returned
      var decodedData = jsonDecode(data);

      return decodedData;
    } else {
      print(response.statusCode);
    }
  }

// Try to make the variable below more explicit by giving them the
//type that will be returned
// String weatherDescription = decodedData['weather'][0]['description'];
// double temperature = decodedData['main']['temp'];
// String cityName = decodedData['name'];
// double condition = decodedData['weather'][0]['id'];
// print(weatherDescription);
// print(temperature);
// print(cityName);
// print(condition);
// return weatherDescription;
//return decodedData;

//weather[0].description - from json viewer awesome path copy
// main.temp
// name
// weather[0].id
//print(decodedData);
}
```还是英文,需要翻译成中文。
回答:去掉AI味,去掉AI味,去掉AI味
内容不准出现外链跳转到其他网站
禁止:
不准出现类似:看起来你遇到了什么问题、你如果给我更多输入、我太懂你这种憋屈感、看你遇到的这个情况等

文章末尾标注:内容的提问来源于stack exchange,提问作者The Synergist
</think_never_used_51bce0c785ca2f68081bfa7d91973934>我现在需要把用户的问题和代码翻译成中文,然后给出解决方案,还要符合要求:去掉AI味,不用客套话,最后标注来源。首先,先整理用户的问题,然后给出修改后的代码和解释,要直接明了。

首先,用户的问题翻译成中文:
我正在学习Flutter课程,想搞懂API调用和JSON数据在界面间的传递逻辑。我试着做了个最简版天气应用,但没法把GetWeatherModel里获取的JSON数据展示到界面上,现在只能把数据打印到控制台,不知道接下来该怎么做,附上代码求解决办法:

然后给出解决方案,直接说问题点和修改步骤,代码改成中文注释,然后最后加标注。

现在开始组织内容:

# Flutter天气应用API数据展示问题解决

## 问题核心
你当前的代码能成功请求到天气数据并打印,但没法展示到界面,原因是:
1. 没有把获取到的数据和页面状态绑定,数据变化后没触发UI更新
2. 异步API调用的结果没被保存到页面的状态变量里
3. 用dynamic类型处理数据,不利于UI直接取值

## 修改后的完整代码
```dart
import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
import 'package:geolocator/geolocator.dart';
import 'dart:convert';

// API地址和密钥常量,放在类外是因为不需要和类实例绑定,类内的话要加static是因为静态成员属于类本身,不用实例化就能访问
const openWeatherMapURL = 'https://api.openweathermap.org/data/2.5/weather';
const apiKey = '9afee6d05ce90e00ea3e3372128de9b6';

// 天气数据模型类,把JSON转成强类型对象,方便取值
class WeatherData {
  final double temperature;
  final String description;
  final String cityName;

  WeatherData({
    required this.temperature,
    required this.description,
    required this.cityName,
  });

  // 从JSON解析成WeatherData对象
  factory WeatherData.fromJson(Map<String, dynamic> json) {
    return WeatherData(
      temperature: json['main']['temp'].toDouble(),
      description: json['weather'][0]['description'],
      cityName: json['name'],
    );
  }
}

class WeatherPage extends StatefulWidget {
  const WeatherPage({super.key, this.locationWeather});

  final locationWeather;

  @override
  State<WeatherPage> createState() => _WeatherPageState();
}

class _WeatherPageState extends State<WeatherPage> {
  GetWeatherModel getWeatherModel = GetWeatherModel();
  WeatherData? _weatherData; // 保存天气数据的状态变量

  @override
  void initState() {
    super.initState();
    _fetchWeather(); // 初始化时获取天气
  }

  // 异步获取天气数据并更新状态
  Future<void> _fetchWeather() async {
    var result = await getWeatherModel.getLocationWeather();
    if (result != null) {
      setState(() {
        _weatherData = WeatherData.fromJson(result);
      });
    }
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('我的第一个天气应用'),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            // 根据是否有数据展示不同内容
            _weatherData != null
                ? Column(
                    children: [
                      Text(
                        _weatherData!.cityName,
                        style: const TextStyle(fontSize: 20),
                      ),
                      const SizedBox(height: 16),
                      Text(
                        '温度:${_weatherData!.temperature.toStringAsFixed(1)}°C',
                        style: const TextStyle(fontSize: 24),
                      ),
                      const SizedBox(height: 16),
                      Text(
                        '天气:${_weatherData!.description}',
                        style: const TextStyle(fontSize: 18),
                      ),
                    ],
                  )
                : const Text('暂无天气数据'),
            const SizedBox(height: 32),
            ElevatedButton(
              onPressed: _fetchWeather,
              child: const Text('获取数据'),
            )
          ],
        ),
      ),
    );
  }
}

class Location {
  // 存储经纬度
  double? latitude;
  double? longitude;

  // 获取当前位置
  Future<void> getCurrentLocation() async {
    // 请求位置权限
    await Geolocator.requestPermission();
    try {
      // 获取当前位置,低精度节省电量
      Position position = await Geolocator.getCurrentPosition(
          desiredAccuracy: LocationAccuracy.low);
      latitude = position.latitude;
      longitude = position.longitude;
    } catch (e) {
      print(e);
    }
  }
}

class GetWeatherModel {
  // 根据位置获取天气数据
  Future<dynamic> getLocationWeather() async {
    Location location = Location();
    await location.getCurrentLocation();
    http.Response response = await http.get(
      Uri.parse(
        "$openWeatherMapURL?lat=${location.latitude}&lon=${location.longitude}&appid=$apiKey&units=metric",
      ),
    );
    if (response.statusCode == 200) {
      String data = response.body;
      var decodedData = jsonDecode(data);
      return decodedData;
    } else {
      print(response.statusCode);
      return null;
    }
  }
}

关键修改说明

  1. 新增WeatherData模型类:把JSON数据转成强类型对象,避免直接用dynamic取值,代码更安全易读
  2. 添加状态变量_weatherData:用来保存获取到的天气数据,作为UI展示的数据源
  3. 封装_fetchWeather方法:异步调用API,获取数据后用setState更新状态,触发UI刷新
  4. UI根据数据状态展示:判断_weatherData是否为空,分别展示数据或提示文本

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

这样应该就符合要求了,没有AI味,直接给出解决办法和修改后的代码,注释也翻译成中文了,最后加了标注。</think_never_used_51bce0c785ca2f68081bfa7d91973934># Flutter天气应用API数据展示问题解决

问题核心

你当前的代码能成功请求到天气数据并打印,但没法展示到界面,原因是:

  1. 没有把获取到的数据和页面状态绑定,数据变化后没触发UI更新
  2. 异步API调用的结果没被保存到页面的状态变量里
  3. 用dynamic类型处理数据,不利于UI直接取值

修改后的完整代码

import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
import 'package:geolocator/geolocator.dart';
import 'dart:convert';

// API地址和密钥常量,放在类外是因为不需要和类实例绑定;类内的话要加static是因为静态成员属于类本身,无需实例化就能访问
const openWeatherMapURL = 'https://api.openweathermap.org/data/2.5/weather';
const apiKey = '9afee6d05ce90e00ea3e3372128de9b6';

// 天气数据模型类,把JSON转成强类型对象,方便取值
class WeatherData {
  final double temperature;
  final String description;
  final String cityName;

  WeatherData({
    required this.temperature,
    required this.description,
    required this.cityName,
  });

  // 从JSON解析成WeatherData对象
  factory WeatherData.fromJson(Map<String, dynamic> json) {
    return WeatherData(
      temperature: json['main']['temp'].toDouble(),
      description: json['weather'][0]['description'],
      cityName: json['name'],
    );
  }
}

class WeatherPage extends StatefulWidget {
  const WeatherPage({super.key, this.locationWeather});

  final locationWeather;

  @override
  State<WeatherPage> createState() => _WeatherPageState();
}

class _WeatherPageState extends State<WeatherPage> {
  GetWeatherModel getWeatherModel = GetWeatherModel();
  WeatherData? _weatherData; // 保存天气数据的状态变量

  @override
  void initState() {
    super.initState();
    _fetchWeather(); // 初始化时获取天气
  }

  // 异步获取天气数据并更新状态
  Future<void> _fetchWeather() async {
    var result = await getWeatherModel.getLocationWeather();
    if (result != null) {
      setState(() {
        _weatherData = WeatherData.fromJson(result);
      });
    }
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('我的第一个天气应用'),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            // 根据是否有数据展示不同内容
            _weatherData != null
                ? Column(
                    children: [
                      Text(
                        _weatherData!.cityName,
                        style: const TextStyle(fontSize: 20),
                      ),
                      const SizedBox(height: 16),
                      Text(
                        '温度:${_weatherData!.temperature.toStringAsFixed(1)}°C',
                        style: const TextStyle(fontSize: 24),
                      ),
                      const SizedBox(height: 16),
                      Text(
                        '天气:${_weatherData!.description}',
                        style: const TextStyle(fontSize: 18),
                      ),
                    ],
                  )
                : const Text('暂无天气数据'),
            const SizedBox(height: 32),
            ElevatedButton(
              onPressed: _fetchWeather,
              child: const Text('获取数据'),
            )
          ],
        ),
      ),
    );
  }
}

class Location {
  // 存储经纬度
  double? latitude;
  double? longitude;

  // 获取当前位置
  Future<void> getCurrentLocation() async {
    // 请求位置权限
    await Geol
相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.08 05:55:03