I have this widget that is getting data from a rest API, below, that works, but before anything is rendered to the screen, it throws up the following error for like a second before showing the data:
LateInitializationError: Field 'person' has not been initialized.
How can I fix this? Fairly new to flutter and any pointers will be appreciated.
Here is my code:
class PersonDetails extends StatefulWidget {
final String id;
PersonDetails({
required this.id,
});
@override
_PersonDetailsState createState() => _PersonDetailsState();
}
class _PersonDetailsState extends State<PersonDetails> {
@override
void initState() {
getPersonDetails();
super.initState();
}
late Person person;
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(person.id.toString()),
),
body: Container(child: Text('you are here')),
);
}
Future<void> getPersonDetails() async {
final params = {
"api_key": "df1555a226ba2b6d6c15c425a626e6bf",
"language": "en-US",
};
Uri url = Uri.https('api.themoviedb.org', '/3/person/${widget.id}', params);
http.Response res = await http.get(url);
person = Person.fromJson(cnv.jsonDecode(res.body));
setState(() {});
}
Here is the data model my API response is being mapped to:
class Person {
bool? adult;
List<String>? alsoKnownAs;
String? biography;
String? birthday;
Null? deathday;
int? gender;
Null? homepage;
int? id;
String? imdbId;
String? knownForDepartment;
String? name;
String? placeOfBirth;
double? popularity;
String? profilePath;
Person(
{this.adult,
this.alsoKnownAs,
this.biography,
this.birthday,
this.deathday,
this.gender,
this.homepage,
this.id,
this.imdbId,
this.knownForDepartment,
this.name,
this.placeOfBirth,
this.popularity,
this.profilePath});
Person.fromJson(Map<String, dynamic> json) {
adult = json['adult'];
alsoKnownAs = json['also_known_as'].cast<String>();
biography = json['biography'];
birthday = json['birthday'];
deathday = json['deathday'];
gender = json['gender'];
homepage = json['homepage'];
id = json['id'];
imdbId = json['imdb_id'];
knownForDepartment = json['known_for_department'];
name = json['name'];
placeOfBirth = json['place_of_birth'];
popularity = json['popularity'];
profilePath = json['profile_path'];
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['adult'] = this.adult;
data['also_known_as'] = this.alsoKnownAs;
data['biography'] = this.biography;
data['birthday'] = this.birthday;
data['deathday'] = this.deathday;
data['gender'] = this.gender;
data['homepage'] = this.homepage;
data['id'] = this.id;
data['imdb_id'] = this.imdbId;
data['known_for_department'] = this.knownForDepartment;
data['name'] = this.name;
data['place_of_birth'] = this.placeOfBirth;
data['popularity'] = this.popularity;
data['profile_path'] = this.profilePath;
return data;
}
getBio() {
return this.biography;
}
}
CodePudding user response:
you could use FutureBuilder as suggested by julemand101 or you could display something else while it's null make.
either way i you have to make Person nullable.
class PersonDetails extends StatefulWidget {
final String id;
const PersonDetails({
Key? key,
required this.id,
}) : super(key: key);
@override
_PersonDetailsState createState() => _PersonDetailsState();
}
class _PersonDetailsState extends State<PersonDetails> {
@override
void initState() {
getPersonDetails();
super.initState();
}
Person? person;
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(person?.id.toString() ?? "..."),
),
body: Container(
child: const Text('you are here'),
),
);
}
Future<void> getPersonDetails() async {
final params = {
"api_key": "df1555a226ba2b6d6c15c425a626e6bf",
"language": "en-US",
};
Uri url = Uri.https('api.themoviedb.org', '/3/person/${widget.id}', params);
http.Response res = await http.get(url);
setState(() {
person = Person.fromJson(cnv.jsonDecode(res.body));
});
}
}
CodePudding user response:
class PersonDetails extends StatefulWidget {
final String id;
PersonDetails({
required this.id,
});
@override
_PersonDetailsState createState() => _PersonDetailsState();
}
class _PersonDetailsState extends State<PersonDetails> {
@override
void initState() {
person=getPersonDetails();
super.initState();
}
late Future<Person> person;
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(person.id.toString()),
),
body: Container(child: Text('you are here')),
);
}
Future<Person> getPersonDetails() async {
final params = {
"api_key": "df1555a226ba2b6d6c15c425a626e6bf",
"language": "en-US",
};
Uri url = Uri.https('api.themoviedb.org',
'/3/person/${widget.id}',
params);
http.Response res = await http.get(url);
if(res.statuscode==200){
Map<String,dynamic>map=jsonDecode(res.body);
return Person.fromjson(map);
}else{
return throw Exception("error occur");
}}
in your code person variable is initialising late because when statefull widget initialize in the init state you are calling the api which take time to fetch data from the server and then that variable is initialized. that is the correct way of doing that or you can make Person nullable when data is fetched from the api you can setstate the variable
