I am running into timing problems, I am getting data from a api, then creating a list from the JSON. I think use the length of the resulting list as the item count in my listview. However it throws a null error on the itemcount and then completes processing and presents the listview. I am trying to find where the timing problem is and how items and widgets are processed so that I can avoid the error. My code is below if anyone has any ideas where my code is flawed.
class Specialty extends StatefulWidget {
Specialty({Key key, this.title}) : super(key: key);
final String title;
@override
_SpecialtyState createState() => new _SpecialtyState();
}
class _SpecialtyState extends State<Specialty> {
bool _dataReceived = false;
bool _authenticated = false;
SharedPreferences prefs;
List mylist;
@override
void initState() {
super.initState();
_getPrefs();
_getSpecialty();
}
_getPrefs() async {
prefs = await SharedPreferences.getInstance();
_authenticated = prefs.getBool('authenticated');
print('AUTH2: ' + _authenticated.toString());
print('AUTHCODE2: ' + prefs.getString('authcode'));
}
_getSpecialty() async {
var _url = 'http://$baseurl:8080/support/specialty';
var http = createHttpClient();
var response = await http.get(_url);
var specialties = jsonCodec.decode(response.body);
mylist = specialties.toList();
//_dataReceived = true;
setState(() {
_dataReceived = true;
});
}
Future<Null> _onRefresh() {
Completer<Null> completer = new Completer<Null>();
Timer timer = new Timer(new Duration(seconds: 3), () {
completer.complete();
});
return completer.future;
}
@override
Widget build(BuildContext context) {
return new Scaffold(
body: new RefreshIndicator(
child: new ListView.builder(
itemBuilder: _itemBuilder,
itemCount: mylist.length,
),
onRefresh: _onRefresh,
));
}
Widget _itemBuilder(BuildContext context, int index) {
Specialties spec = getSpec(index);
return new SpecialtyWidget(spec: spec,);
}
Specialties getSpec(int index) {
return new Specialties(
mylist[index]['id'], mylist[index]['name'], mylist[index]['details'],
new Photo('lib/images/' + mylist[index]['image'], mylist[index]['name'],
mylist[index]['name']));
//return new Specialties.fromMap(mylist[index]);
}
var jsonCodec = const JsonCodec();
}
You should use await
when invoking your async
methods. You can mark initState
as async
, it will still override.
Make sure to call setState()
whenever you mutate member variables.
Check if (mounted)
before setState
if you are doing it after an async wait, because the widget may no longer be visible.
Consider using FutureBuilder
instead of setState
when doing async programming.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With