'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.

  1. Delete the repo from github (optional step and dangerous)
  2. In the root directory of your local repo, show hidden files and delete the .git folder.
  3. Restart visual studio.
  4. 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