Reputation: 595
I having this message error from my console from android studio:
════════ (3) Exception caught by widgets library ═══════════════════════════════════════════════════
The method '[]' was called on null.
Receiver: null
Tried calling: [](0)
The relevant error-causing widget was:
FutureBuilder<dynamic> file:///home/developer/projects/PaladinsStats/lib/screens/transferencia/formulario.dart:26:15
════════════════════════════════════════════════════════════════════════════════════════════════════
But when my request has a response, my page just load normal. Usually i put a checker to see if the objects is null to render but i don't know what is happening here. I think he is trying access a null variable, but the builder wait the future to render? If no, how can i made the builder wait the future?
My code:
import 'dart:async';
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
import '../../models/champion.dart';
class FormularioTransferencia extends StatefulWidget {
final Champion champion;
const FormularioTransferencia({Key key, @required this.champion})
: super(key: key);
@override
State<StatefulWidget> createState() {
return FormularioTransferenciaState();
}
}
class FormularioTransferenciaState extends State<FormularioTransferencia> {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.champion.feName),
),
body: FutureBuilder(
future: fetchPost(widget.champion.feName),
builder: (context, snapshot) {
final champion = json.decode(snapshot.data.toString());
return SingleChildScrollView(
child: Column(
children: <Widget>[
Image.network(
'https://web2.hirez.com/paladins/champion-headers/' +
champion[0]['slug'] +
'.png'),
],
),
);
},
));
}
fetchPost(championName) async {
final response = await http.get(
'https://cms.paladins.com/wp-json/wp/v2/champions?slug=' +
championName.replaceAll(' ', '-').toLowerCase() +
'&lang_id=1');
if (response.statusCode == 200) {
// If the call to the server was successful, parse the JSON
return response.body;
} else {
// If that call was not successful, throw an error.
throw Exception('Failed to load post');
}
}
}
Dart model:
class Champion {
int id;
String name;
String feName;
String title;
String role;
String feRole;
String image;
String latest;
Champion(
{this.id,
this.name,
this.feName,
this.title,
this.role,
this.feRole,
this.image,
this.latest});
Champion.fromJson(Map<String, dynamic> json) {
id = json['id'];
name = json['name'];
feName = json['feName'];
title = json['title'];
role = json['role'];
feRole = json['feRole'];
image = json['image'];
latest = json['latest'];
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['id'] = this.id;
data['name'] = this.name;
data['feName'] = this.feName;
data['title'] = this.title;
data['role'] = this.role;
data['feRole'] = this.feRole;
data['image'] = this.image;
data['latest'] = this.latest;
return data;
}
}
Upvotes: 1
Views: 1237
Reputation: 1348
Add the 6 lines below.
body: FutureBuilder(
future: fetchPost(widget.champion.feName),
builder: (context, snapshot) {
if (snapshot.hasData) { // add this line
final champion = json.decode(snapshot.data.toString());
return SingleChildScrollView(
child: Column(
children: <Widget>[
Image.network(
'https://web2.hirez.com/paladins/champion-headers/' +
champion[0]['slug'] +
'.png'),
],
),
);
} else { // add this line
return Center( // add this line
child: CircularProgressIndicator(), // add this line
); // add this line
} // add this line
},
));
Upvotes: 1
Reputation: 420
you can use
if(!snapshot.hasData) {
return CircularProgressIndicator();
}
else {
return SingleChildScrollView(
child: Column(
children: <Widget>[
Image.network(
'https://web2.hirez.com/paladins/champion-headers/' +
champion[0]['slug'] +
'.png'),
],
),
);
}
Upvotes: 1
Reputation: 2645
The first time build() is called snapshot.data is null. When the future method returns a value the widget gets rebuild.
Therefor you should do something like this:
return FutureBuilder(
future:
getSomeFuture(),
builder: (context, snapshot) {
if (snapshot.data == null) { //<-- Add this condition
return Container();
} else {
return MyWidget(snapshot.data);
}
}
);
EDIT:
And if you want to make this look nice, use a loading animation as temporarily placeholder and make sure that it has the same height/width as the widget that gets build when the future is returned.
Upvotes: 3