我有一些错误:
I/flutter (30216): NoSuchMethodError: 在 null 上调用了方法“[]”。 I/flutter (30216):接收器:空 我/颤振(30216):尝试调用:
这是我的 main.dart 代码:
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:flutter_weather/models/additionalWeatherData.dart';
import 'package:flutter_weather/models/geocode.dart';
import 'package:geolocator/geolocator.dart';
import 'package:http/http.dart' as http;
import 'package:latlong2/latlong.dart';
import '../models/dailyWeather.dart';
import '../models/hourlyWeather.dart';
import '../models/weather.dart';
class WeatherProvider with ChangeNotifier {
String apiKey = '744b94562476e3686d8944d72c0bb1f2';
late Weather weather;
late AdditionalWeatherData additionalWeatherData;
LatLng? currentLocation;
List<HourlyWeather> hourlyWeather = [];
List<DailyWeather> dailyWeather = [];
bool isLoading = false;
bool isRequestError = false;
bool isSearchError = false;
bool isLocationserviceEnabled = false;
LocationPermission? locationPermission;
bool isCelsius = true;
String get measurementUnit => isCelsius ? '°C' : '°F';
Future<Position?> requestLocation(BuildContext context) async {
isLocationserviceEnabled = await Geolocator.isLocationServiceEnabled();
notifyListeners();
if (!isLocationserviceEnabled) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text('Location service disabled')),
);
return Future.error('Location services are disabled.');
}
locationPermission = await Geolocator.checkPermission();
if (locationPermission == LocationPermission.denied) {
isLoading = false;
notifyListeners();
locationPermission = await Geolocator.requestPermission();
if (locationPermission == LocationPermission.denied) {
ScaffoldMessenger.of(context).showSnackBar(SnackBar(
content: Text('Permission denied'),
));
return Future.error('Location permissions are denied');
}
}
if (locationPermission == LocationPermission.deniedForever) {
isLoading = false;
notifyListeners();
ScaffoldMessenger.of(context).showSnackBar(SnackBar(
content: Text(
'Location permissions are permanently denied, Please enable manually from app settings',
),
));
return Future.error('Location permissions are permanently denied');
}
return await Geolocator.getCurrentPosition();
}
Future<void> getWeatherData(
BuildContext context, {
bool notify = false,
}) async {
isLoading = true;
isRequestError = false;
isSearchError = false;
if (notify) notifyListeners();
Position? locData = await requestLocation(context);
if (locData == null) {
isLoading = false;
notifyListeners();
return;
}
try {
currentLocation = LatLng(locData.latitude, locData.longitude);
await getCurrentWeather(currentLocation!);
await getDailyWeather(currentLocation!);
} catch (e) {
print(e);
isRequestError = true;
} finally {
isLoading = false;
notifyListeners();
}
}
Future<void> getCurrentWeather(LatLng location) async {
Uri url = Uri.parse(
'https://api.openweathermap.org/data/2.5/weather?lat=${location.latitude}&lon=${location.longitude}&units=metric&appid=$apiKey',
);
try {
final response = await http.get(url);
final extractedData = json.decode(response.body) as Map<String, dynamic>;
weather = Weather.fromJson(extractedData);
print('Fetched Weather for: ${weather.city}/${weather.countryCode}');
} catch (error) {
print(error);
isLoading = false;
this.isRequestError = true;
}
}
Future<void> getDailyWeather(LatLng location) async {
isLoading = true;
notifyListeners();
Uri dailyUrl = Uri.parse(
'https://api.openweathermap.org/data/2.5/onecall?lat=${location.latitude}&lon=${location.longitude}&units=metric&exclude=minutely,current&appid=$apiKey',
);
try {
final response = await http.get(dailyUrl);
final dailyData = json.decode(response.body) as Map<String, dynamic>;
additionalWeatherData = AdditionalWeatherData.fromJson(dailyData);
List dailyList = dailyData['daily'];
List hourlyList = dailyData['hourly'];
hourlyWeather = hourlyList
.map((item) => HourlyWeather.fromJson(item))
.toList()
.take(24)
.toList();
dailyWeather =
dailyList.map((item) => DailyWeather.fromDailyJson(item)).toList();
} catch (error) {
print(error);
isLoading = false;
this.isRequestError = true;
}
}
Future<GeocodeData?> locationToLatLng(String location) async {
try {
Uri url = Uri.parse(
'http://api.openweathermap.org/geo/1.0/direct?q=$location&limit=5&appid=$apiKey',
);
final http.Response response = await http.get(url);
if (response.statusCode != 200) return null;
return GeocodeData.fromJson(
jsonDecode(response.body)[0] as Map<String, dynamic>,
);
} catch (e) {
print(e);
return null;
}
}
Future<void> searchWeather(String location) async {
isLoading = true;
notifyListeners();
isRequestError = false;
print('search');
try {
GeocodeData? geocodeData;
geocodeData = await locationToLatLng(location);
if (geocodeData == null) throw Exception('Unable to Find Location');
await getCurrentWeather(geocodeData.latLng);
await getDailyWeather(geocodeData.latLng);
// replace location name with data from geocode
// because data from certain lat long might return local area name
weather.city = geocodeData.name;
} catch (e) {
print(e);
isSearchError = true;
} finally {
isLoading = false;
notifyListeners();
}
}
void switchTempUnit() {
isCelsius = !isCelsius;
notifyListeners();
}
}
我尝试在网络中找到解决方案,但我看不到类似的东西。我从 GitHub 上获取了这个应用程序的开源项目,但没有任何关于它的文章。
了解错误发生在哪一行会有所帮助,但如果没有这些详细信息,我们仍然可以找到问题的潜在根源。
提供的代码示例中似乎有两个值是对
[]
运算符的调用的接收者,dailyData
和 jsonDecode(response.body)[0] as Map<String, dynamic>
。
dailyData
初始化为:
final dailyData = json.decode(response.body) as Map<String, dynamic>;
这两种情况下的问题是,您将
json.decode(response.body)
的结果(即 dynamic
值)转换为 Map
,而没有检查所转换的值实际上是 Map
。在这种情况下,看起来至少在您的一种情况下 json.decode(response.body)
的结果实际上是 null
,因此不能成为 []
呼叫的接收者。
这对你来说可能是个好主意
json.decode(response.body)
之前先检查 Map
的值,以确保它看起来像您所期望的那样Map<String, dynamic>?
,请注意类型后面的 ?
),并让编译器告诉您在哪里执行 null 不安全的操作jsonDecode(response.body)[0] as Map<String, dynamic> ?? <String, dynamic>{}
(尽管最后一点我还没有测试过,也不是100%确定)