I want to fetch and print datas from this json file:
[{"id": "76d751584e134ebf854bebda8998334b", "data": {"timestamp": "15/05/2021-13:08:38", "temperature": 21.9, "pressure": 1007.4342535, "humidity": 43.994442131}}, {"id": "6188e169eeda4547b3e87414d50664df", "data": {"timestamp": "15/05/2021-15:08:38", "temperature": 22.28, "pressure": 1006.47539066, "humidity": 46.1434366089}}, {"id": "4eb75a12fd6c4eb8a94b20106aab4e2a", "data": {"timestamp": "15/05/2021-17:08:38", "temperature": 22.71, "pressure": 1006.52941164, "humidity": 47.7676641555}}]
This is my flutter code witch is supposed to do the job:
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
class SensorData with ChangeNotifier {
//final id;
final timestamp;
final temperature;
final pressure;
final humidity;
SensorData({
//@required this.id,
@required this.timestamp,
@required this.temperature,
@required this.pressure,
@required this.humidity,
});
factory SensorData.fromJson(Map<String, dynamic> json) {
return new SensorData(
//id: json['id'] as String,
timestamp: json['timestamp'] as String,
temperature: json['temperature'] as double,
pressure: json['pressure'] as double,
humidity: json['humidity'] as double,
);
}
}
class App extends StatefulWidget {
@override
_AppState createState() => _AppState();
}
class _AppState extends State<App> {
Future<List<SensorData>> fetchSensorDatas() async {
final http.Response response = await http.get(Uri.http(<my_API_url>));
var responseJson = json.decode(response.body);
return (responseJson['data'] as List)
.map((p) => SensorData.fromJson(p))
.toList();
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: new Container(
child: new Column(
children: [
new Container(
height: 200,
),
new ListView(
children: <Widget>[
new FutureBuilder<List<SensorData>>(
future: fetchSensorDatas(),
builder: (context, snapshot) {
if (snapshot.hasData){
List<SensorData> posts = snapshot.data;
return new Column(
children: posts.map((post) => new Column(
children: <Widget>[
new Text(post.temperature),
],
)).toList()
);
}
else if(snapshot.hasError)
{
return snapshot.error;
}
return new Center(
child: new Column(
children: <Widget>[
new Padding(padding: new EdgeInsets.all(50.0)),
new CircularProgressIndicator(),
],
),
);
},
),
],
),
],
),
),
);
}
}
I have 2 errors:
Where am I getting wrong?
Many thanks in advance!!
snapshot.data returns me "A value of type 'List?' can't be assigned to a variable of type 'List'."
The problem is inside the fetchSensorDatas
method. Since responseJson
is a Map
, every time you access a key from it, there is a possibility that this key does not exist and it'll return null (therefore returning the nullable type List?
). If you are sure that the key exists, you can do the following:
final List data = responseJson['data']! as List;
return data.map((p) => SensorData.fromJson(p)).toList();
snapshot.error returns me "The return type 'Object?' isn't a 'Widget', as required by the closure's context.".
That's because you're returning multiple types inside the builder
parameter of FutureBuilder
, and therefore the return type of it will be the common ascestor of all types being returned, which in this case is Object
. Note that you're returning a Column
in the first condition, an Error
in the second condition and a Center
in the third condition. You can replace the second return with some Wigdet
:
else if (snapshot.hasError){
// Alternative 1: return a Text widget with the error message
return Text(snapshot.error?.toString() ?? "");
// Alternative 2: print the error message and return an empty widget
print(snapshot.error);
return SizedBox.shrink();
// Alternative 3: display the user that an error has occurred with a descriptive widget
return Text("An error has occured.");
// Alternative 4: rethrow the error
throw snapshot.error;
}
I figured it out!
First of all my model was very poor, so I rewrote it like this:
import 'dart:convert';
List<SensorData> sensorDataFromJson(String str) => List<SensorData>.from(json.decode(str).map((x) => SensorData.fromJson(x)));
String sensorDataToJson(List<SensorData> data) => json.encode(List<dynamic>.from(data.map((x) => x.toJson())));
class SensorData {
SensorData({
required this.id,
required this.data,
});
String id;
Data data;
factory SensorData.fromJson(Map<String, dynamic> json) => SensorData(
id: json["id"],
data: Data.fromJson(json["data"]),
);
Map<String, dynamic> toJson() => {
"id": id,
"data": data.toJson(),
};
}
class Data {
Data({
required this.timestamp,
required this.temperature,
required this.pressure,
required this.humidity,
});
String timestamp;
double temperature;
double pressure;
double humidity;
factory Data.fromJson(Map<String, dynamic> json) => Data(
timestamp: json["timestamp"],
temperature: json["temperature"].toDouble(),
pressure: json["pressure"].toDouble(),
humidity: json["humidity"].toDouble(),
);
Map<String, dynamic> toJson() => {
"timestamp": timestamp,
"temperature": temperature,
"pressure": pressure,
"humidity": humidity,
};
}
Then I have a method returning the get request:
Future<List<SensorData>> getSensorDatas() async {
final response = await http.get(Uri.http('192.168.1.3:5000', '/pigarden/'));
return sensorDataFromJson(response.body);
}
And finally my app file looks like this:
FutureBuilder<List<SensorData>>(
future: SensorDatasRepository().getSensorDatas(),
builder: (context, snapshot) {
if (snapshot.hasError) {
showDialog(
context: context,
builder : (BuildContext context) => const AlertDialog(
title: Text("Error"),
content: Text('An error has occured...'),
),
);
} else if (snapshot.hasData) {
return ListView.builder(
itemCount: snapshot.data!.length,
itemBuilder: (context, index) => ListTile(
title: Text(snapshot.data![index].id),
subtitle: Text(
snapshot.data![index].data.temperature.toString(),
softWrap: false,
overflow: TextOverflow.ellipsis,
),
),
);
}
return Center(
child: CircularProgressIndicator(),
);
},
),
And now it works just fine!
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.