14

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"]),
          );
          },),
    );
  }
}
nujabse
  • 151
  • 1
  • 1
  • 7
  • 1
    Where do you call `setState`? I can't see it in your code. – Günter Zöchbauer May 25 '18 at 10:47
  • How do you use your state? – Phuc Tran May 25 '18 at 10:51
  • I reedited the question, sorry for my mistake – nujabse May 25 '18 at 10:51
  • @Phuc Tran I want to use the `_data` list to build a listview widget, but the parsed `_data` doesn't get passed to the state. – nujabse May 25 '18 at 11:00
  • What file contains above code? When you add `print(_data);` after `_data = ...;` is the expected data printed? – Günter Zöchbauer May 25 '18 at 11:01
  • The file contains a simple json file in the code listed above. When I add `print(_data)` after `_data = json.decode(jsonFile.readAsStringSync());` , the contents in `_data` got printed out, but not working in the listview widget. – nujabse May 25 '18 at 11:09
  • Does `lib/main.dart` contain any imports that don't start with `import 'package:...` or `import 'dart:...`? Also please add the output of `flutter doctor` to your question. – Günter Zöchbauer May 25 '18 at 12:03
  • @GünterZöchbauer The outputs of `flutter doctor` don't have any warnings. I finally found out the problem originates from incorrect json file format. Anyway, I really appreciate your tips and suggestions! – nujabse May 28 '18 at 10:48

4 Answers4

10

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.

Danny Tuppeny
  • 40,147
  • 24
  • 151
  • 275
1

As mentioned in this post, use

WidgetsBinding.instance.addPostFrameCallback((_) => setState(...));

instead of just

setState(...)
Tiago Martins Peres
  • 14,289
  • 18
  • 86
  • 145
1

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;
        });
     }
Venjal
  • 41
  • 8
0

EDIT* Sorry i was wrong, you can call async method from initState(), just call it without await

@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 :
    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

Dwi Kurnianto M
  • 427
  • 3
  • 6
  • 1
    You cant call `getData` with `await`. `initState` would need to be async for that – MohitC May 19 '22 at 17:45
  • Oh yes you are right thank you @MohitC, don't forget to add `Future initState() async {}` – Dwi Kurnianto M Aug 05 '22 at 08:04
  • Yeah I dont think `initState` can be async mate – MohitC Aug 06 '22 at 17:55
  • ah sorry for the confusion, btw you can just remove the `await getData()` and call it `getData()` instead. more check here : https://stackoverflow.com/questions/61764400/state-initstate-must-be-a-void-method-without-an-async-keyword – Dwi Kurnianto M Feb 18 '23 at 11:29