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

Clima天气应用报错LateInitializationError:latitude字段未初始化求助

Clima天气应用初始化错误排查与修复

错误信息

[ERROR:flutter/lib/ui/ui_dart_state.cc(198)] Unhandled Exception: LateInitializationError: Field 'latitude' has not been initialized.
E/flutter (24924): #0      Location.latitude (package:clima/services/location.dart)
E/flutter (24924): #1      WeatherModel.getLocationWeather (package:clima/services/weather.dart:23:25)
E/flutter (24924): #2      _LoadingScreenState.getLocationData (package:clima/screens/loading_screen.dart:22:23)

问题根源

  1. 未初始化的late变量:Location类中用late修饰latitude和longitude,但当getCurrentLocation因权限缺失、定位失败等异常抛出时,这两个变量不会被赋值,后续访问直接触发初始化错误。
  2. 异常处理缺失闭环:getCurrentLocation仅打印异常,未处理定位失败后的逻辑,导致后续代码仍尝试访问未初始化的变量。
  3. 定位权限未配置:Geolocator库需要定位权限,若未在项目配置中声明或动态请求,会直接导致定位失败。

解决方案

1. 重构Location类,替换late为可空类型

将latitude和longitude改为可空类型,同时增加权限检查与定位结果返回:

import 'package:geolocator/geolocator.dart';

class Location{
  double? longitude;
  double? latitude;

  Future<bool> getCurrentLocation() async {
    try {
      // 检查并请求定位权限
      LocationPermission permission = await Geolocator.checkPermission();
      if (permission == LocationPermission.denied) {
        permission = await Geolocator.requestPermission();
        if (permission == LocationPermission.denied) {
          return false;
        }
      }

      Position position = await Geolocator.getCurrentPosition(desiredAccuracy: LocationAccuracy.low);
      latitude = position.latitude;
      longitude = position.longitude;
      return true;
    } catch (exception) {
      print(exception);
      return false;
    }
  }
}

2. 修改WeatherModel,增加定位有效性检查

在创建网络请求前,确认定位是否成功:

import 'package:clima/services/location.dart';
import 'package:clima/services/networking.dart';

const String apiKey = '304dd36c502250baab7c7f8216ec4ff2';
const String openWeatherMapURL = 'https://api.openweathermap.org/data/2.5/weather';

class WeatherModel {
  Future<dynamic> getCityWeather(String cityName) async {
    NetworkHelper networkHelper = NetworkHelper('$openWeatherMapURL?q=$cityName&appid=$apiKey&units=metric');
    var weatherData = await networkHelper.getData();
    return weatherData;
  }

  Future<dynamic> getLocationWeather() async {
    Location location = Location();
    bool isLocationSuccess = await location.getCurrentLocation();

    // 校验定位结果有效性
    if (!isLocationSuccess || location.latitude == null || location.longitude == null) {
      return null;
    }

    NetworkHelper networkHelper = NetworkHelper('$openWeatherMapURL?lat=${location.latitude}&lon=${location.longitude}&appid=$apiKey&units=metric');
    var weatherData = await networkHelper.getData();
    return weatherData;
  }

  // 以下方法保持不变
  String getWeatherIcon(int condition) {
    if (condition < 300) {
      return '🌩';
    } else if (condition < 400) {
      return '🌧';
    } else if (condition < 600) {
      return '☔️';
    } else if (condition < 700) {
      return '☃️';
    } else if (condition < 800) {
      return '🌫';
    } else if (condition == 800) {
      return '☀️';
    } else if (condition <= 804) {
      return '☁️';
    } else {
      return '🤷‍';
    }
  }

  String getMessage(int temp) {
    if (temp > 25) {
      return 'It\'s 🍦 time';
    } else if (temp > 20) {
      return 'Time for shorts and 👕';
    } else if (temp < 10) {
      return 'You\'ll need 🧣 and 🧤';
    } else {
      return 'Bring a 🧥 just in case';
    }
  }
}

3. 配置定位权限

  • Android:在android/app/src/main/AndroidManifest.xml中添加权限:
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
  • iOS:在ios/Runner/Info.plist中添加:
<key>NSLocationWhenInUseUsageDescription</key>
<string>需要获取您的位置来显示当地天气</string>
<key>NSLocationAlwaysUsageDescription</key>
<string>需要获取您的位置来显示当地天气</string>

4. 优化LoadingScreen的异常处理

定位失败时显示提示,避免无效跳转:

import 'package:flutter/material.dart';
import 'package:clima/screens/location_screen.dart';
import 'package:clima/services/weather.dart';
import 'package:flutter_spinkit/flutter_spinkit.dart';

class LoadingScreen extends StatefulWidget {
  @override
  State<StatefulWidget> createState() {
    return _LoadingScreenState();
  }
}

class _LoadingScreenState extends State<LoadingScreen> {
  @override
  void initState() {
    super.initState();
    getLocationData();
  }

  void getLocationData() async {
    WeatherModel weatherModel = WeatherModel();
    var weatherData = await weatherModel.getLocationWeather();

    if (weatherData == null) {
      ScaffoldMessenger.of(context).showSnackBar(
        const SnackBar(content: Text('定位失败,请检查权限或重试')),
      );
      return;
    }

    Navigator.push(
      context,
      MaterialPageRoute(
        builder: (context) => LocationScreen(
          locationWeather: weatherData,
        ),
      ),
    );
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Center(
        child: SpinKitSpinningLines(
          color: Colors.white,
          size: 50.0,
        ),
      ),
    );
  }
}

额外优化点

  • LocationScreen中替换固定文本为动态变量:
// 替换温度与图标组件
Text(
  '$temperature°',
  style: kTempTextStyle,
),
Text(
  weatherIcon,
  style: kConditionTextStyle,
),

// 替换底部提示文本
Text(
  "$weatherMessage in $cityName!",
  textAlign: TextAlign.right,
  style: kMessageTextStyle,
),
  • CityScreen中修正Null为Dart关键字小写null:
if(typedName != null) {
  var weatherData = await weather.getCityWeather(typedName);
  updateUI(weatherData);
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.25 05:54:16