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

Flutter开发天气应用报latitude字段LateInitializationError未初始化错误

Flutter 天气应用LateInitializationError 字段未初始化问题解决

报错信息

LateError (LateInitializationError: Field 'latitude' has not been initialized.)

问题复现代码

import 'package:flutter/material.dart';
import 'package:climate/services/location.dart';
import 'package:http/http.dart' as http;
import 'dart:convert';

const apiKey = '78c0a5319f932d3e171aa34ab51dd7e3';

class LoadingScreen extends StatefulWidget {
  @override
  _LoadingScreenState createState() => _LoadingScreenState();
}

class _LoadingScreenState extends State<LoadingScreen> {
  late double latitude;
  late double longitude;
  @override
  void initState() {
    super.initState();
    getLocation();
  }

  void getLocation() async {
    Location location = Location();
    await location.getCurrentLocation();
    latitude = location.latitude;
    longitude = location.longitude;
  }

  void getData() async {
    http.Response reponse = await http.get(Uri.parse(
        "https://api.openweathermap.org/data/2.5/weather?lat=$latitude&lon=$longitude&appid=$apiKey"));

    if (reponse.statusCode == 200) {
      String data = reponse.body;

      int condition = jsonDecode(data)['weather'][0]['id'];
      print(condition);
      double temp = jsonDecode(data)['main']['temp']; //main.temp
      print(temp);
      String city = jsonDecode(data)['name']; //name
      print(city);
    } else {
      print(reponse.statusCode);
    }
    print(reponse.body);
  }

  @override
  Widget build(BuildContext context) {
    getData();
    return Scaffold();
  }
}

问题原因

  • late关键字的作用是承诺非空字段会在首次被访问前完成赋值,不会在类实例创建时强制要求初始化,但如果访问时还没赋值就会抛出LateInitializationError。
  • 代码执行时序错误:initState中调用的getLocation()是异步方法,内部await getCurrentLocation()需要等待系统定位返回才会给latitude、longitude赋值,但build方法会在initState执行结束后立刻触发,此时定位还未返回,build中直接调用getData()访问两个未赋值的late字段,直接触发报错。
  • 逻辑位置错误:build方法会在组件生命周期内被多次触发(状态更新、父组件重绘、键盘弹出等场景),将网络请求getData()写在build中会导致重复发起无效请求。
  • 移除late触发编译错误是Dart空安全机制的强制要求:非空类型的类字段必须在声明时、构造函数初始化列表中完成赋值,既不初始化、也不用late标记延迟初始化,就会直接编译失败。

修复方案

核心原则:所有副作用逻辑(定位、网络请求)放在initState或事件回调中,不要放在build方法里;严格保证访问字段前异步赋值逻辑已经执行完成,用加载态做过渡。
修复后可运行代码:

import 'package:flutter/material.dart';
import 'package:climate/services/location.dart';
import 'package:http/http.dart' as http;
import 'dart:convert';

const apiKey = '78c0a5319f932d3e171aa34ab51dd7e3';

class LoadingScreen extends StatefulWidget {
  @override
  _LoadingScreenState createState() => _LoadingScreenState();
}

class _LoadingScreenState extends State<LoadingScreen> {
  bool isLoading = true;
  // 用可空类型承接未赋值状态,比late更安全,空指针风险会被编译器提示
  double? latitude;
  double? longitude;
  dynamic weatherData;

  @override
  void initState() {
    super.initState();
    // 初始化时串行执行定位、拉取天气逻辑
    fetchLocationAndWeather();
  }

  Future<void> fetchLocationAndWeather() async {
    try {
      Location location = Location();
      await location.getCurrentLocation();
      latitude = location.latitude;
      longitude = location.longitude;
      // 拿到经纬度后再发起天气请求,此时字段必然已经赋值
      await getWeatherData();
    } catch (e) {
      print('获取数据异常: $e');
    } finally {
      // 组件未销毁时才更新状态
      if (mounted) {
        setState(() {
          isLoading = false;
        });
      }
    }
  }

  Future<void> getWeatherData() async {
    // 空值兜底,避免异常
    if (latitude == null || longitude == null) return;
    // 修正原代码拼写错误:reponse -> response
    http.Response response = await http.get(Uri.parse(
        "https://api.openweathermap.org/data/2.5/weather?lat=$latitude&lon=$longitude&appid=$apiKey"));

    if (response.statusCode == 200) {
      String data = response.body;
      weatherData = jsonDecode(data);
      int condition = weatherData['weather'][0]['id'];
      print(condition);
      double temp = weatherData['main']['temp'];
      print(temp);
      String city = weatherData['name'];
      print(city);
    } else {
      print('请求失败,状态码: ${response.statusCode}');
    }
    print(response.body);
  }

  @override
  Widget build(BuildContext context) {
    // build方法仅做UI渲染,根据加载状态返回不同组件
    return Scaffold(
      body: Center(
        child: isLoading 
          ? const CircularProgressIndicator() 
          : const Text('天气数据加载完成'),
      ),
    );
  }
}

额外优化说明

  • 用可空类型double?替代late double,编译器会自动提示空判断逻辑,比late的运行时报错更安全。
  • 增加加载状态,定位、请求过程中显示加载指示器,避免空白页。
  • 增加异常捕获和空值兜底,避免定位权限拒绝、网络异常时直接崩溃。
  • 异步更新状态前判断mounted属性,避免组件销毁后调用setState触发内存泄漏和报错。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.03 08:31:21