Dart核心特性实战:天气API数据解析教程
时间:2026-08-21 | 作者:电竞小硕 | 阅读:0上一节课我们学习了单元测试,掌握了通过全面测试保证代码质量的方法。
今天,我们将进入第 24 课 —— 核心特性实战:天气 API 数据解析。
通过这个实战项目,我们会综合运用 Dart 的多个核心特性,包括 HTTP 请求、异步编程、JSON 解析和空安全处理,打造一个能获取并展示天气数据的小应用。
一、项目需求
目标很明确:创建一个 Dart 应用程序,用来获取并展示天气数据。
- 调用公共 API:我们将使用 Open - Meteo API。它的优势在于,对于非商业用途,无需注册获取 API 密钥,可直接使用,能轻松获取天气数据。
- 获取天气数据:我们希望检索特定位置的当前天气信息。位置可以通过地理坐标(纬度和经度)或者在某些情况下通过城市名称来指定。
- 解析 JSON 数据:API 返回的数据采用 JSON 格式。我们需要将此 JSON 数据转换为 Dart 对象,以便在应用程序中方便地处理。
- 展示天气信息:解析数据后,我们将以有意义的方式展示相关天气信息,如温度、天气描述、湿度等。
二、技术要点
1. Dart 中的 HTTP 请求
在 Dart 中,有多种发送 HTTP 请求的方式。
最常用的方式之一是使用http包。首先,我们需要在pubspec.yaml文件中添加它作为依赖:
dependencies:
http: ^1.4.0
然后,运行dart pub get安装该包。
下面是一个向 Open - Meteo API 发送简单 GET 请求的示例。假设我们要获取某个具有特定坐标位置的天气。
import 'package:http/http.dart' as http;
import 'dart:convert';
Future<String> getWeatherData(double latitude, double longitude) async {
final url = Uri.https('api.open-meteo.com', 'v1/forecast', {
'latitude': latitude.toString(),
'longitude': longitude.toString(),
'current_weather': 'true',
});
final response = await http.get(url);
if (response.statusCode == 200) {
return response.body;
} else {
throw Exception('获取天气数据失败');
}
}
这段代码的核心逻辑如下:
- 导入
http包和dart:convert库,后续解析 JSON 时会用到后者。 - 定义了一个
Future函数getWeatherData。Future关键字表明此函数是异步的,会在未来某个时刻返回结果。 - 使用
Uri.https构建 API 请求的 URL。传入基础 URL、API 端点(这里是/v1/forecast)以及查询参数,如纬度、经度和是否获取当前天气的标识。 - 使用
http.get方法发送 GET 请求到 API。由于这是一个异步操作,使用await关键字。await会暂停函数的执行,直到http.get操作完成并返回一个response。 - 检查响应的
statusCode是否为 200(表示请求成功)。如果是,返回响应体(即包含 JSON 格式天气数据的字符串)。否则,抛出一个Exception表示请求失败。
2. Future 与异步编程
在 Dart 中,异步操作不会立即完成。
例如,HTTP 请求需要通过网络与服务器通信,因此需要一些时间。Dart 使用Future来表示异步操作的结果,而不是在等待请求完成时阻塞程序执行。
在上述getWeatherData函数中,函数本身返回一个Future。
这意味着函数的结果,也就是 JSON 格式的天气数据字符串,将在未来可用。
当在async函数内部使用await关键字时,我们是在告诉 Dart:等到Future完成后,再继续执行后续代码。
例如,在getWeatherData函数中,await http.get(url)语句会暂停函数,直到 HTTP 请求完成,然后将结果赋值给response变量。
如果不使用await,直接返回http.get(url)而不等待它,函数会立即返回一个未完成的Future。
这不是我们想要的,因为我们需要实际的天气数据来进行后续的解析和展示。
下面再看一个示例,帮助理解Future的工作原理:
Future<int> delayAndReturn() async {
await Future.delayed(Duration(seconds: 2));
return 42;
}
void main() async {
print('在调用delayAndReturn之前');
int result = await delayAndReturn();
print('结果是:$result');
print('在调用delayAndReturn之后');
}
在这段代码中,delayAndReturn函数使用Future.delayed暂停 2 秒,然后返回值 42。
在main函数中,我们先打印一条消息,再await delayAndReturn的结果。
等待结果期间,程序不会阻塞。如果还有其他代码,它们可以继续执行。
一旦delayAndReturn中的Future完成,我们打印结果,然后再打印另一条消息。
3. JSON 到模型的转换
从 API 获取到 JSON 格式的天气数据后,我们需要将其转换为 Dart 对象。
这样做之后,数据处理会更方便。
首先,定义一个 Dart 类来表示天气数据。
为简单起见,这里使用一个基本的Weather类,它包含温度和天气描述:
class Weather {
final double temperature;
final String description;
Weather({required this.temperature, required this.description});
factory Weather.fromJson(Map<String, dynamic> json) {
double temp = json['current_weather']['temperature'] 0.0;
String desc = json['current_weather']['weathercode'] != null
getWeatherDescription(json['current_weather']['weathercode'])
: '未知';
return Weather(temperature: temp, description: desc);
}
// 辅助函数,根据天气代码获取天气描述
static String getWeatherDescription(int weathercode) {
// 这里可以根据Open - Meteo的天气代码表进行映射
// 例如:
switch (weathercode) {
case 0:
return '晴朗';
case 1:
return '大部分晴朗';
// 其他代码的映射...
default:
return '未知';
}
}
}
这个Weather类主要包含以下内容:
- 定义了两个最终属性
temperature和description,用于存储相关的天气信息。 - 构造函数接受这两个属性作为必需参数。
fromJson工厂构造函数用于从 JSON 映射创建一个Weather对象。在 Open - Meteo API 响应中,温度位于current_weather对象内,天气代码也在current_weather中。我们使用空感知运算符()为可能缺失的字段提供默认值。对于天气描述,通过调用辅助函数getWeatherDescription,根据天气代码获取对应的文字描述。
现在,我们可以修改getWeatherData函数,使其返回一个Weather对象,而不是 JSON 字符串:
Future getWeatherData(double latitude, double longitude) async {
final url = Uri.https('api.open - meteo.com', 'v1/forecast', {
'latitude': latitude.toString(),
'longitude': longitude.toString(),
'current_weather': 'true',
});
final response = await http.get(url);
if (response.statusCode == 200) {
Map<String, dynamic> json = jsonDecode(response.body);
return Weather.fromJson(json);
} else {
throw Exception('获取天气数据失败');
}
}
这里,我们使用dart:convert库中的jsonDecode函数,将response.body中的 JSON 字符串转换为 Dart 的Map。
然后把这个映射传递给Weather类的fromJson工厂构造函数,创建一个Weather对象。
三、空安全处理
在使用像 Open - Meteo 这样的外部 API 时,处理空值非常重要。
API 响应可能并不总是包含我们期望的所有数据,也可能由于网络问题导致返回空响应。
1. 网络数据的空值处理
在getWeatherData函数中,我们已经有了一些基本的空安全处理。
当 HTTP 请求失败(statusCode不是 200)时,我们抛出一个Exception,而不是返回可能为空或不正确的结果。
不过,我们还可以添加更详细的错误处理。
例如,如果 API 返回的数据格式不正确,我们可以进一步处理。在fromJson工厂构造函数中,可以增加对数据完整性的检查:
factory Weather.fromJson(Map<String, dynamic> json) {
if (!json.containsKey('current_weather')) {
throw Exception('API返回的数据格式不正确,缺少current_weather字段');
}
double temp = json['current_weather']['temperature'] 0.0;
String desc = json['current_weather']['weathercode']!= null
getWeatherDescription(json['current_weather']['weathercode'])
: '未知';
return Weather(temperature: temp, description: desc);
}
在这个更新后的fromJson构造函数中,我们先检查 JSON 映射是否包含current_weather键。
如果不包含,说明数据格式有问题,此时抛出一个Exception。
2. JSON 解析中的空感知运算符
正如在fromJson构造函数中所看到的那样,当我们从JSON映射中提取值时,使用了空感知运算符()。
比如说,double temp = json['current_weather']['temperature'] 0.0;。
这样做的好处是,如果在current_weather对象中不存在temperature这个键,我们就会使用默认值0.0。
这样不会得到一个可能导致运行时错误的空值。
类似地,对于天气描述,通过检查天气代码是否存在,来决定是获取描述还是使用默认值未知。
这种方式可以有效避免因数据缺失而导致的程序崩溃。
四、整合代码
下面创建一个简单的基于控制台的 Dart 应用程序,展示这些概念如何协同工作。
import 'package:http/http.dart' as http;
import 'dart:convert';
class Weather {
final double temperature;
final String description;
Weather({required this.temperature, required this.description});
factory Weather.fromJson(Map<String, dynamic> json) {
if (!json.containsKey('current_weather')) {
throw Exception('API返回的数据格式不正确,缺少current_weather字段');
}
double temp = json['current_weather']['temperature'] 0.0;
String desc = json['current_weather']['weathercode'] != null
getWeatherDescription(json['current_weather']['weathercode'])
: '未知';
return Weather(temperature: temp, description: desc);
}
static String getWeatherDescription(int weathercode) {
switch (weathercode) {
case 0:
return '晴朗';
case 1:
return '大部分晴朗';
// 其他代码的映射...
default:
return '未知';
}
}
}
Future getWeatherData(double latitude, double longitude) async {
final url = Uri.https('api.open-meteo.com', 'v1/forecast', {
'latitude': latitude.toString(),
'longitude': longitude.toString(),
'current_weather': 'true',
});
final response = await http.get(url);
if (response.statusCode == 200) {
Map<String, dynamic> json = jsonDecode(response.body);
return Weather.fromJson(json);
} else {
throw Exception('获取天气数据失败');
}
}
void main() async {
double latitude = 34.0522; // 示例纬度,可替换为你需要的
double longitude = -118.2437; // 示例经度,可替换为你需要的
try {
Weather weather = await getWeatherData(latitude, longitude);
print('该位置的天气是:${weather.description}');
print('温度是:${weather.temperature} °C');
} catch (e) {
print('错误:$e');
}
}
在这个main函数中:
- 我们首先定义了示例的纬度和经度。在实际应用中,你可以根据需要修改这些值,或者通过用户输入获取。
- 使用
try - catch块处理在 API 调用或 JSON 解析过程中可能出现的任何异常。 - 在
try块内,awaitgetWeatherData函数的结果。如果操作成功,打印天气描述和温度。 - 如果发生异常(如网络错误、API 返回的数据格式错误等),在
catch块中打印错误消息。
五、进一步改进
1. 错误日志记录
目前,我们只是简单地打印错误消息。
在实际应用中,将错误记录到文件或日志服务中会更好。
这样,我们可以在以后查看错误,并更有效地进行调试。
例如,可以使用logging包来实现更高级的日志记录功能。
2. 用户输入功能
现在我们是硬编码了纬度和经度。
我们可以通过dart:io库实现用户输入功能,让用户输入城市名称或坐标。
然后根据用户输入来查询天气。例如:
import 'dart:io';
void main() async {
stdout.write('请输入纬度:');
String latitudeStr = stdin.readLineSync();
stdout.write('请输入经度:');
String longitudeStr = stdin.readLineSync();
if (latitudeStr != null && longitudeStr != null) {
double latitude = double.tryParse(latitudeStr) 0.0;
double longitude = double.tryParse(longitudeStr) 0.0;
try {
Weather weather = await getWeatherData(latitude, longitude);
print('该位置的天气是:${weather.description}');
print('温度是:${weather.temperature} °C');
} catch (e) {
print('错误:$e');
}
} else {
print('请输入有效的纬度和经度');
}
}
3. 用户界面集成
若想让用户体验更为出色,不妨把天气数据检索功能融入到图形用户界面中。
要是采用Flutter框架,就能创建出一个精美的应用程序。
借助各种小部件,可以以一种有序且极具视觉吸引力的方式来展示天气信息。
- 例如,运用
ListView来呈现不同的天气信息字段。 - 利用
Image.network来显示与天气状况相匹配的图标等等。
免责声明:文中图文均来自网络,如有侵权请联系删除,心愿游戏发布此文仅为传递信息,不代表心愿游戏认同其观点或证实其描述。
相关文章
更多-
- Scala 类入门:主构造器、字段可变性与方法定义一次看懂
- 时间:2026-08-23
精选合集
更多大家都在玩
大家都在看
更多-
- 糖尿病完全不能吃糖吗
- 时间:2026-09-15
-
- 蚂蚁庄园小课堂2026年9月16日最新题目答案
- 时间:2026-09-15
-
- 小鸡答题今天的答案是什么2026年9月16日
- 时间:2026-09-15
-
- 蚂蚁庄园每日答题答案2026年9月16日
- 时间:2026-09-15
-
- 以下哪种粮食是酿造绍兴黄酒的主要原料 蚂蚁庄园今日答案9月16日
- 时间:2026-09-15
-
- 劝学名句“及时当勉励,岁月不待人”出自哪位诗人 蚂蚁庄园今日答案9.16
- 时间:2026-09-15
-
- 蚂蚁庄园今天答题答案2026年9月16日
- 时间:2026-09-15
-
- 蚂蚁庄园答题今日答案2026年9月16日
- 时间:2026-09-15
