Flutter天气应用请求返回404且数据为Null问题求助
天气应用404错误及Null返回问题
跟着Udemy平台的Flutter入门课程开发天气应用,前期运行正常,完成当前章节后应用返回Null。热重启后日志显示404状态码及null,更换新API Key后问题依旧,课程较老旧无人答疑。
错误日志
Performing hot restart... Syncing files to device moto g52... Restarted application in 2,126ms. I/flutter (13494): 404 I/flutter (13494): null
相关代码文件
main.dart
import 'package:clima/screens/location_screen.dart'; import 'package:flutter/material.dart'; import 'package:clima/screens/loading_screen.dart'; void main() => runApp(MyApp()); class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { return MaterialApp( theme: ThemeData.dark(), home: LoadingScreen(), ); } }
location_screen.dart
import 'package:flutter/material.dart'; import 'package:clima/utilities/constants.dart'; class LocationScreen extends StatefulWidget { LocationScreen({this.locationWeather}); final locationWeather; @override _LocationScreenState createState() => _LocationScreenState(); } class _LocationScreenState extends State<LocationScreen> { @override void initState() { super.initState(); print(widget.locationWeather); } @override Widget build(BuildContext context) { return Scaffold( body: Container( decoration: BoxDecoration( image: DecorationImage( image: AssetImage('images/location_background.jpg'), fit: BoxFit.cover, colorFilter: ColorFilter.mode( Colors.white.withOpacity(0.8), BlendMode.dstATop), ), ), constraints: BoxConstraints.expand(), child: SafeArea( child: Column( mainAxisAlignment: MainAxisAlignment.spaceBetween, crossAxisAlignment: CrossAxisAlignment.stretch, children: <Widget>[ Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: <Widget>[ TextButton( onPressed: () {}, child: Icon( Icons.near_me, size: 50.0, ), ), TextButton( onPressed: () {}, child: Icon( Icons.location_city, size: 50.0, ), ), ], ), Padding( padding: EdgeInsets.only(left: 15.0), child: Row( children: <Widget>[ Text( '32°', style: kTempTextStyle, ), Text( '☀️', style: kConditionTextStyle, ), ], ), ), Padding( padding: EdgeInsets.only(right: 15.0), child: Text( "It's 🍦 time in San Francisco!", textAlign: TextAlign.right, style: kMessageTextStyle, ), ), ], ), ), ), ); } }
loading_screen.dart
import 'package:clima/screens/location_screen.dart'; import 'package:flutter/material.dart'; import 'package:clima/services/location_handler.dart'; import 'package:clima/services/networking.dart'; import 'location_screen.dart'; import 'package:flutter_spinkit/flutter_spinkit.dart'; const myAPI = '7c8b4449639ae2b6b5e3bfd67a0e350f'; class LoadingScreen extends StatefulWidget { @override _LoadingScreenState createState() => _LoadingScreenState(); } class _LoadingScreenState extends State<LoadingScreen> { late double latitood; late double longitood; void initState() { super.initState(); getLocationData(); } void getLocationData() async { Locator loca = Locator(); await loca.getCurrentLocation(); latitood = loca.latitude; longitood = loca.longitude; NetworkHelper NetHelp = NetworkHelper( 'https://api.openweathermap.org/data/2.5.weather?lat=$latitood&lon=$longitood&appid=$myAPI'); var weatherDataFinal = await NetHelp.getData(); Navigator.push(context, MaterialPageRoute(builder: (context) { return LocationScreen( locationWeather: weatherDataFinal); //creating a path to location_screen.dart //and passing/pushing weather data to location screen through a constructor. })); } @override Widget build(BuildContext context) { return Scaffold( body: Center( child: SpinKitDoubleBounce( color: Colors.white, size: 100, ), ), ); } }
networking.dart
import 'dart:convert'; //imported to convert/use JSON data into our project. import 'package:http/http.dart' as http; class NetworkHelper { NetworkHelper(this.url); final String url; Future getData() async { http.Response response = await http.get(Uri.parse(url)); //Passing the 'url' which is a String, will be converted into URI using 'Uri.parse' method. if (response.statusCode == 200) { String data = response.body; var decodedData = jsonDecode(data); //decoding and putting data into decodedData variable of dynamic type. return decodedData; } else { print(response.statusCode); print('Something\'s wrong I can feel it.'); } } }
location_handler.dart
import 'package:geolocator/geolocator.dart'; class Locator { late double latitude; late double longitude; Future<void> getCurrentLocation() async { try { Position posi = await Geolocator.getCurrentPosition( desiredAccuracy: LocationAccuracy.low); latitude = posi.latitude; longitude = posi.longitude; } on Exception catch (e) { print(e); } } }
依赖包
- geolocator: ^7.0.2
- http: ^0.13.1
- flutter_spinkit: ^5.1.0
问题排查与解决方案
1. 核心问题:API请求URL格式错误
404错误直接指向请求路径无效,查看loading_screen.dart中的API URL:
原路径为https://api.openweathermap.org/data/2.5.weather?lat=...
正确的OpenWeatherMap API路径应为https://api.openweathermap.org/data/2.5/weather?lat=...
修正方法:将URL中的2.5.weather改为2.5/weather
2. 完善位置获取的异常处理
当前location_handler.dart中,若位置获取失败,latitude和longitude作为late变量未被初始化,会导致后续请求出现非法参数。
优化代码:
class Locator { double? latitude; double? longitude; Future<void> getCurrentLocation() async { try { Position posi = await Geolocator.getCurrentPosition( desiredAccuracy: LocationAccuracy.low); latitude = posi.latitude; longitude = posi.longitude; } on Exception catch (e) { print(e); latitude = null; longitude = null; } } }
同时在loading_screen.dart中添加位置校验:
void getLocationData() async { Locator loca = Locator(); await loca.getCurrentLocation(); if(loca.latitude == null || loca.longitude == null){ print("无法获取位置信息"); return; } latitood = loca.latitude!; longitood = loca.longitude!; // 后续请求代码... }
3. 处理网络请求的错误返回
networking.dart中,非200状态码时未返回值,导致weatherDataFinal为null,传递到LocationScreen后打印null。
优化代码:
Future getData() async { http.Response response = await http.get(Uri.parse(url)); if (response.statusCode == 200) { String data = response.body; var decodedData = jsonDecode(data); return decodedData; } else { print(response.statusCode); print('请求失败'); return null; // 显式返回null } }
内容的提问来源于stack exchange,提问作者Sagar Jadhav
相关产品推荐
相关产品推荐

