Flutter 如何 JSON 序列化数据表单 api



我正在尝试在我的颤振应用程序中使用模型来在我的应用程序中启动并运行这个概念。我对OOP很陌生,所以我想尽可能多地学习。我的问题是我有来自OpenWeather API的API响应,我的方法正在调用api获取数据。这工作正常,我通常使用 JSON 手动解码和手动访问属性 天气["主要"] aa。但我想要的是按模型分解/预处理我的 JSON。下面的代码运行良好,但我想应用使用 JSON 序列化的概念,我不知道如何开始。我所有的尝试都失败了...:/

我已经在我之前的答案的帮助下 https://app.quicktype.io/生成了模型。

型:

import 'dart:convert';
Forcast forcastFromJson(String str) => Forcast.fromJson(json.decode(str));
String forcastToJson(Forcast data) => json.encode(data.toJson());
class Forcast {
String cod;
double message;
int cnt;
List<ListElement> list;
City city;
Forcast({
this.cod,
this.message,
this.cnt,
this.list,
this.city,
});
factory Forcast.fromJson(Map<String, dynamic> json) => new Forcast(
cod: json["cod"],
message: json["message"].toDouble(),
cnt: json["cnt"],
list: new List<ListElement>.from(
json["list"].map((x) => ListElement.fromJson(x))),
city: City.fromJson(json["city"]),
);
Map<String, dynamic> toJson() => {
"cod": cod,
"message": message,
"cnt": cnt,
"list": new List<dynamic>.from(list.map((x) => x.toJson())),
"city": city.toJson(),
};
}
class City {
int id;
String name;
Coord coord;
String country;
City({
this.id,
this.name,
this.coord,
this.country,
});
factory City.fromJson(Map<String, dynamic> json) => new City(
id: json["id"],
name: json["name"],
coord: Coord.fromJson(json["coord"]),
country: json["country"],
);
Map<String, dynamic> toJson() => {
"id": id,
"name": name,
"coord": coord.toJson(),
"country": country,
};
}
class Coord {
double lat;
double lon;
Coord({
this.lat,
this.lon,
});
factory Coord.fromJson(Map<String, dynamic> json) => new Coord(
lat: json["lat"].toDouble(),
lon: json["lon"].toDouble(),
);
Map<String, dynamic> toJson() => {
"lat": lat,
"lon": lon,
};
}
class ListElement {
int dt;
MainClass main;
List<Weather> weather;
Clouds clouds;
Wind wind;
Sys sys;
DateTime dtTxt;
Rain rain;
Rain snow;
ListElement({
this.dt,
this.main,
this.weather,
this.clouds,
this.wind,
this.sys,
this.dtTxt,
this.rain,
this.snow,
});
factory ListElement.fromJson(Map<String, dynamic> json) => new ListElement(
dt: json["dt"],
main: MainClass.fromJson(json["main"]),
weather: new List<Weather>.from(
json["weather"].map((x) => Weather.fromJson(x))),
clouds: Clouds.fromJson(json["clouds"]),
wind: Wind.fromJson(json["wind"]),
sys: Sys.fromJson(json["sys"]),
dtTxt: DateTime.parse(json["dt_txt"]),
rain: json["rain"] == null ? null : Rain.fromJson(json["rain"]),
snow: json["snow"] == null ? null : Rain.fromJson(json["snow"]),
);
Map<String, dynamic> toJson() => {
"dt": dt,
"main": main.toJson(),
"weather": new List<dynamic>.from(weather.map((x) => x.toJson())),
"clouds": clouds.toJson(),
"wind": wind.toJson(),
"sys": sys.toJson(),
"dt_txt": dtTxt.toIso8601String(),
"rain": rain == null ? null : rain.toJson(),
"snow": snow == null ? null : snow.toJson(),
};
}
class Clouds {
int all;
Clouds({
this.all,
});
factory Clouds.fromJson(Map<String, dynamic> json) => new Clouds(
all: json["all"],
);
Map<String, dynamic> toJson() => {
"all": all,
};
}
class MainClass {
double temp;
double tempMin;
double tempMax;
double pressure;
double seaLevel;
double grndLevel;
int humidity;
double tempKf;
MainClass({
this.temp,
this.tempMin,
this.tempMax,
this.pressure,
this.seaLevel,
this.grndLevel,
this.humidity,
this.tempKf,
});
factory MainClass.fromJson(Map<String, dynamic> json) => new MainClass(
temp: json["temp"].toDouble(),
tempMin: json["temp_min"].toDouble(),
tempMax: json["temp_max"].toDouble(),
pressure: json["pressure"].toDouble(),
seaLevel: json["sea_level"].toDouble(),
grndLevel: json["grnd_level"].toDouble(),
humidity: json["humidity"],
tempKf: json["temp_kf"].toDouble(),
);
Map<String, dynamic> toJson() => {
"temp": temp,
"temp_min": tempMin,
"temp_max": tempMax,
"pressure": pressure,
"sea_level": seaLevel,
"grnd_level": grndLevel,
"humidity": humidity,
"temp_kf": tempKf,
};
}
class Rain {
double the3H;
Rain({
this.the3H,
});
factory Rain.fromJson(Map<String, dynamic> json) => new Rain(
the3H: json["3h"] == null ? null : json["3h"].toDouble(),
);
Map<String, dynamic> toJson() => {
"3h": the3H == null ? null : the3H,
};
}
class Sys {
Pod pod;
Sys({
this.pod,
});
factory Sys.fromJson(Map<String, dynamic> json) => new Sys(
pod: podValues.map[json["pod"]],
);
Map<String, dynamic> toJson() => {
"pod": podValues.reverse[pod],
};
}
enum Pod { D, N }
final podValues = new EnumValues({"d": Pod.D, "n": Pod.N});
class Weather {
int id;
MainEnum main;
Description description;
String icon;
Weather({
this.id,
this.main,
this.description,
this.icon,
});
factory Weather.fromJson(Map<String, dynamic> json) => new Weather(
id: json["id"],
main: mainEnumValues.map[json["main"]],
description: descriptionValues.map[json["description"]],
icon: json["icon"],
);
Map<String, dynamic> toJson() => {
"id": id,
"main": mainEnumValues.reverse[main],
"description": descriptionValues.reverse[description],
"icon": icon,
};
}
enum Description {
CLEAR_SKY,
BROKEN_CLOUDS,
LIGHT_RAIN,
MODERATE_RAIN,
FEW_CLOUDS
}
final descriptionValues = new EnumValues({
"broken clouds": Description.BROKEN_CLOUDS,
"clear sky": Description.CLEAR_SKY,
"few clouds": Description.FEW_CLOUDS,
"light rain": Description.LIGHT_RAIN,
"moderate rain": Description.MODERATE_RAIN
});
enum MainEnum { CLEAR, CLOUDS, RAIN }
final mainEnumValues = new EnumValues({
"Clear": MainEnum.CLEAR,
"Clouds": MainEnum.CLOUDS,
"Rain": MainEnum.RAIN
});
class Wind {
double speed;
double deg;
Wind({
this.speed,
this.deg,
});
factory Wind.fromJson(Map<String, dynamic> json) => new Wind(
speed: json["speed"].toDouble(),
deg: json["deg"].toDouble(),
);
Map<String, dynamic> toJson() => {
"speed": speed,
"deg": deg,
};
}
class EnumValues<T> {
Map<String, T> map;
Map<T, String> reverseMap;
EnumValues(this.map);
Map<T, String> get reverse {
if (reverseMap == null) {
reverseMap = map.map((k, v) => new MapEntry(v, k));
}
return reverseMap;
}
}

进行 API 调用的网络:

import 'package:http/http.dart' as http;
import 'dart:convert';
class NetworkHelper {
NetworkHelper({this.text});
String text;
String apiKey = '';
Future<dynamic> getData(text) async {
http.Response response = await http.get(
'https://api.openweathermap.org/data/2.5/weather?q=$text&appid=$apiKey&units=metric');
if (response.statusCode == 200) {
var decodedData = jsonDecode(response.body);
return decodedData;
} else {
print(response.statusCode);
}
}
Future<dynamic> getForcast(text) async {
http.Response response = await http.get(
'http://api.openweathermap.org/data/2.5/forecast?q=${text}&units=metric&appid=$apiKey');
if (response.statusCode == 200) {
var decodedData = jsonDecode(response.body);
return decodedData;
} else {
print(response.statusCode);
}
}
Future<dynamic> getDataLocation(lat, lon) async {
http.Response response = await http.get(
'https://api.openweathermap.org/data/2.5/weather?lat=$lat&lon=$lon&appid=$apiKey&units=metric');
if (response.statusCode == 200) {
var decodedData = jsonDecode(response.body);
return decodedData;
} else {
print(response.statusCode);
}
}
Future<dynamic> getForcastLocation(lat, lon) async {
http.Response response = await http.get(
'http://api.openweathermap.org/data/2.5/forecast?lat=$lat&lon=$lon&units=metric&appid=$apiKey');
if (response.statusCode == 200) {
var decodedData = jsonDecode(response.body);
return decodedData;
} else {
print(response.statusCode);
}
}
}

显示数据的天气:

import 'package:flutter/material.dart';
import 'package:weather/common/format.dart';
import 'package:weather/service/Network.dart';
import 'package:weather/service/location.dart';
class Weather extends StatefulWidget {
Weather({this.text});
final String text;
_WeatherState createState() => _WeatherState();
}
class _WeatherState extends State<Weather> {
NetworkHelper networkHelper = NetworkHelper();
Location location = Location();
Formats formats = Formats();
int temperature;
String cityName;
String description;
bool isLoading = true;
dynamic newData;
String city;
@override
void initState() {
super.initState();
city = widget.text;
buildUI(city);
}
buildUI(String text) async {
var weatherData = await networkHelper.getData(text);
var forecastData = await networkHelper.getForcast(text);
double temp = weatherData['main']['temp'];
temperature = temp.toInt();
cityName = weatherData['name'];
description = weatherData['weather'][0]['description'];
newData = forecastData['list'].toList();
setState(() {
isLoading = false;
});
}
buildUIByLocation() async {
await location.getCurrentLocation();
var weatherLocation = await networkHelper.getDataLocation(
location.latitude, location.longitude);
var forcastLocation = await networkHelper.getForcastLocation(
location.latitude, location.longitude);
double temp = weatherLocation['main']['temp'];
temperature = temp.toInt();
cityName = weatherLocation['name'];
description = weatherLocation['weather'][0]['description'];
newData = forcastLocation['list'].toList();
setState(() {
isLoading = false;
});
}
Widget get _pageToDisplay {
if (isLoading == true) {
return _loadingView;
} else {
return _weatherView;
}
}
Widget get _loadingView {
return Center(child: CircularProgressIndicator());
}
Widget get _weatherView {
return SafeArea(
child: Column(
children: <Widget>[
Flexible(
flex: 1,
child: Container(
margin: EdgeInsets.fromLTRB(12, 1, 30, 0),
decoration: new BoxDecoration(
color: Color(0xff4556FE),
borderRadius: BorderRadius.all(Radius.circular(10.0)),
boxShadow: [
BoxShadow(
color: Color(0xFFD4DAF6),
offset: Offset(20, 20),
),
BoxShadow(
color: Color(0xFFadb6ff),
offset: Offset(10, 10),
),
],
),
child: Row(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Expanded(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
Text(
'$cityName',
style: TextStyle(fontSize: 25, color: Colors.white),
),
SizedBox(
height: 5,
),
Text(
'$temperature°C',
style: TextStyle(fontSize: 50, color: Colors.white),
),
],
),
),
Expanded(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
Text(
'$description',
style: TextStyle(fontSize: 25, color: Colors.white),
),
],
),
)
],
),
),
),
SizedBox(
height: 30,
),
Flexible(
flex: 2,
child: Container(
margin: EdgeInsets.fromLTRB(12, 10, 12, 0),
decoration: new BoxDecoration(
color: Color(0xff4556FE),
borderRadius: BorderRadius.vertical(top: Radius.circular(10.0)),
),
child: ListView.builder(
padding: const EdgeInsets.all(8.0),
itemCount: newData.length,
itemBuilder: (BuildContext context, int index) {
return Container(
margin: const EdgeInsets.all(4.0),
height: 50,
child: Center(
child: Row(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: <Widget>[
Text(
formats.readTimeStamp(newData[index]['dt']),
style: TextStyle(
color: Colors.white, fontSize: 14),
),
Text(
newData[index]['weather'][0]['main'].toString(),
style: TextStyle(
color: Colors.white,
fontSize: 18,
fontWeight: FontWeight.w600),
),
Text(
formats.floatin(newData[index]['main']['temp']),
style: TextStyle(
color: Colors.white,
fontSize: 16,
fontWeight: FontWeight.w600),
),
],
),
));
}),
),
),
],
),
);
}
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
actions: <Widget>[
IconButton(
padding: EdgeInsets.fromLTRB(0, 0, 20, 0),
icon: Icon(Icons.autorenew, color: Colors.black, size: 30),
onPressed: () {
if (city == "") {
setState(() {
isLoading = true;
buildUIByLocation();
});
} else {
setState(() {
isLoading = true;
buildUI(city);
});
}
},
),
IconButton(
padding: EdgeInsets.fromLTRB(0, 0, 15, 0),
icon: Icon(
Icons.location_on,
color: Colors.black,
size: 30,
),
onPressed: () async {
setState(() {
city = '';
isLoading = true;
});
await buildUIByLocation();
},
)
],
leading: IconButton(
icon: Icon(Icons.arrow_back_ios, color: Colors.black),
onPressed: () {
Navigator.pop(context);
},
),
elevation: 0,
backgroundColor: Colors.transparent,
title: const Text(
'Change location',
style: TextStyle(color: Colors.black),
),
),
body: Stack(
children: <Widget>[
Container(
decoration: BoxDecoration(color: Color(0xFFfafafa)),
child: Padding(
padding: const EdgeInsets.fromLTRB(5, 20, 5, 0),
child: Center(child: _pageToDisplay),
),
)
],
),
);
}
}

这是一个非常基本的例子。在这里,您可以看到汽车模型类及其基本属性。数据将由CarRepository类获取,此类执行网络工作并将数据从json映射到模型。 CarScreen 类是一个有状态的小部件,在 initState 之后调用 CarRepository。如果从网络获取数据,汽车将显示在列表中。 获取时会显示加载指示器。

import 'dart:convert';
import 'package:http/http.dart' as http;
class Car {
//
// Attributes
//
int id;
String name;
String color;
int speed;
//
// Constructor
//
Car({
@required this.id,
@required this.name,
@required this.color,
@required this.speed,
});
// convert Json to an car object object
factory Car.fromJson(Map<String, dynamic> json) {
return Car(
id: json['id'] as int,
name: json['name'] as String,
color: json['color'] as String,
speed: json['speed'] as int,
);
}
}
class CarRepository {
/// Load all cars form api and will convert it
/// to an list of cars.
///
///  {
///     "results": [
///         {
///           "id": 1,
///           "name": "Tesla Model 3",
///           "color": "red",
///           "speed": 225
///         },
///         {
///           "id": 3,
///           "name": "Tesla Model S",
///           "color": "black",
///           "speed": 255
///         }
///     ]
///  }
///
///
static Future<List<Car>> fetchAll() async {
String query = '';
String url = Uri.encodeFull("https://xxx.de/api/cars" + query);
final response = await http.get(url);
if (response.statusCode == 200) {
Map data = json.decode(response.body);
final cars = (data['results'] as List).map((i) => new Car.fromJson(i));
return cars.toList();
} else {
return [];
}
}
}
class CarsScreen extends StatefulWidget {
_CarsScreenState createState() => _CarsScreenState();
}
class _CarsScreenState extends State<CarsScreen> {
bool _isLoading = true;
List<Car> _cars = [];
@override
void initState() {
super.initState();
fetchCars();
}
Future fetchCars() async {
_cars = await CarRepository.fetchAll();
setState(() {
_isLoading = false;
});
}
@override
Widget build(BuildContext context) {
if (_isLoading) {
return Scaffold(
appBar: AppBar(
title: Text('Cars'),
),
body: Container(
child: Center(
child: CircularProgressIndicator(),
),
),
);
} else {
return Scaffold(
appBar: AppBar(
title: Text('Cars'),
),
body: ListView.builder(
itemCount: _cars.length,
itemBuilder: (context, index) {
Car car = _cars[index];
return ListTile(
title: Text(car.name),
subtitle: Text(car.color),
);
},
),
);
}
}
}

此示例包括带有汽车对象的嵌套数组。我希望它会有所帮助。

生产者和汽车之间有关系。

import 'dart:convert';
import 'package:http/http.dart' as http;

class CarRepository {
/// Load all producers form api and will convert it
/// to an list of producers.
///   [
///     {
///       "id": 1,
///       "name": "Tesla"
///       "cars": [
///           {
///           "id": 1,
///           "name": "Tesla Model 3",
///           "color": "red",
///           "speed": 225
///         },
///         {
///           "id": 3,
///           "name": "Tesla Model S",
///           "color": "black",
///           "speed": 255
///         }
///         ]
///     },
///     {
///       "id": 2,
///       "name": "Volkswagen"
///       "cars": [
///           {
///             "id": 1,
///             "name": "Golf",
///             "color": "red",
///             "speed": 225
///           },
///           {
///             "id": 3,
///             "name": "Passat",
///             "color": "black",
///             "speed": 255
///           }
///        ]
///     }
///   ]
///
///
static Future<List<Car>> fetchAll() async {
String query = '';
String url = Uri.encodeFull("https://xxx.de/api/producers" + query);
final response = await http.get(url);
if (response.statusCode == 200) {
Map data = json.decode(response.body);
final cars = (data as List).map((i) => new Car.fromJson(i));
return cars.toList();
} else {
return [];
}
}
}

class Producer {
//
// Attributes
//
int id;
String name;
List<Car> cars;
//
// Constructor
//
Producer({
@required this.id,
@required this.name,
@required this.cars,
});
// convert Json to an producer object object
factory Producer.fromJson(Map<String, dynamic> json) {
return Producer(
id: json['id'] as int,
name: json['name'] as String,
cars: (json['cars'] as List ?? []).map((c) {
return Car.fromJson(c);
}).toList(),
);
}
}
class Car {
//
// Attributes
//
int id;
String name;
String color;
int speed;
//
// Constructor
//
Car({
@required this.id,
@required this.name,
@required this.color,
@required this.speed,
});
// convert Json to an car object object
factory Car.fromJson(Map<String, dynamic> json) {
return Car(
id: json['id'] as int,
name: json['name'] as String,
color: json['color'] as String,
speed: json['speed'] as int,
);
}
}

最新更新