'setState() is not working in async calls in flutter
I'm trying to read a json file named mood.json
and parse it to a list named "data", but when I run setState()
, the data
never changed, any help about this problem? The code looks like this:
class DisplayPage extends StatefulWidget {
@override
_DisplayPageState createState() => new _DisplayPageState();
}
class _DisplayPageState extends State<DisplayPage> {
List _data = [];
Directory dir;
File jsonFile;
String jsonPath;
Future getData() async {
dir = await getApplicationDocumentsDirectory();
jsonPath = dir.path + "/" + "mood.json";
jsonFile = new File(jsonPath);
setState(() {
_data = json.decode(jsonFile.readAsStringSync());
});
}
@override
void initState() {
super.initState();
getData();
print(_data.length);
}
@override
Widget build(BuildContext context) {
return new Scaffold(
appBar: new AppBar(
title: new Text('Mood')
),
body: new ListView.builder(
itemCount: _data.length,
itemBuilder: (BuildContext context, int index) {
return new Card(
child: new Text(_data[index]["title"]),
);
},),
);
}
}
Solution 1:[1]
I think your problem may be something else; I took your code and changed the network call to just wait 5 seconds and then return some dummy data and it worked fine.
Future getData() async {
await new Future.delayed(const Duration(seconds: 5));
setState(() {
_data = [
{"title": "one"},
{"title": "two"},
];
});
}
You should put a breakpoint inside your setState
call to ensure it's actually being called and that the data being assigned to _data
is as you expect.
Solution 2:[2]
Hold on mate. lets take a look to your code here :
@override
void initState() {
super.initState();
/// getData(); /// this is an async method, and it's return a future.
/// you can use await instead so the code bellow getData() method execution
/// will be waiting for it to complete first.
/// Here it is :
await getData();
print(_data.length); /// This print now will waiting until the getData completed
}
here is some references : https://dart.dev/codelabs/async-await#working-with-futures-async-and-await
Solution 3:[3]
As mentioned in this post, use
WidgetsBinding.instance.addPostFrameCallback((_) => setState(...));
instead of just
setState(...)
Solution 4:[4]
You should use "async" outside "setState" method.
Note: Use "await" for waitting for the response.
Future getData() async {
dir = await getApplicationDocumentsDirectory();
jsonPath = dir.path + "/" + "mood.json";
jsonFile = new File(jsonPath);
//Use async outside
var json = await json.decode(jsonFile.readAsStringSync());
//Change values on setState
setState(() {
_data = json;
});
}
Solution 5:[5]
I was able to fix this by recreating the repo. BE VERY CAREFUL WHILE DOING THIS.
- Delete the repo from github (optional step and dangerous)
- In the root directory of your local repo, show hidden files and delete the .git folder.
- Restart visual studio.
- Recreate the repo from visual studio.
This is probably NOT the best answer, it worked for me. But there was some bug in my git repo not allowing it see me as the owner of the repo.
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | Danny Tuppeny |
Solution 2 | Dwi Kurnianto M |
Solution 3 | Tiago Martins Peres |
Solution 4 | Daniel Alves |
Solution 5 |