我正在尝试在flutter应用程序中使用模型,以使该概念在我的应用程序中运行。我是OOP的新手,所以我想学习更多。我的问题是我有来自OpenWeather API的API响应,我的方法是调用api获取数据。效果很好,我通常使用JSON手动进行人工解码并通过人工天气[“ main”]来访问属性。但是我想要按模型分解/预处理我的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),
),
)
],
),
);
}
}
答案 0 :(得分:2)
这是一个非常基本的示例。在这里,您可以看到Car模型类及其基本属性。数据将由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),
);
},
),
);
}
}
}
答案 1 :(得分:1)
此示例包括带有汽车对象的嵌套数组。希望对您有所帮助。
生产者与汽车之间存在某种关系。
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,
);
}
}