Search code examples
flutterdartdart-async

Call async functions in build method flutter


I need to get the text wrote inside a ".txt" file, save it in a variable and give it to a Text, inside a TextField. The idea is to write the user input in a ".txt" file so he can read what he wrote when needed on the TextField.

All works, when I read the file it takes the right content but when I store it in a variable to use it Text(var_name...) well what I read on the screen is "Instance of 'Future'".

I know this problem comes from a bad handling of async and future but I would like to really understand why this isn't working.

This is my code :

Future<String> get _localPath async {
 final directory = await getApplicationDocumentsDirectory();
 return directory.path;
}

Future<File> get _localBio async {
 final path = await _localPath;
 print(path);
 return File('$path/bio.txt');
}

Future<File> _write(String text, String filename) async {
final file = await _localBio;

// Write the file.
return file.writeAsString(text);
}

Future<String> _read() async {
  try {
    final file = await _localBio;
     String body = await file.readAsString();
  // Read the file.
    return body;
  } catch (e) {
  // If encountering an error, return 0.
    return "Can't read";
  }
}

Future<String>_MyRead() async {
 String read_ = await _read();
 print(read_);
 return read_;
}

Please write a full answer, I tried a lots of video, forums...Don't just tell me to do var str= _MyRead().then((value) => value); Maybe it can be the answer but please write 2 more lines because I want to understand why this isn't working. I took the code from dev official documentation.


Solution

  • You are using an asynchronous value in a rendering process (the build function of a stateful/stateless widget) which is synchronous. You can't just put a Future of String into a place of a String. It won't work. Why? Because it is of a different type, and you need special methods to convert a variable from one type to another.

    In this case, you might want to transform this Future into a String asynchronously during the build process. You can use a FutureBuilder for that.

    return FutureBuilder<String>(
      future: _myRead,
      builder: (context, snapshot) {
        if (snapshot.hasData) {
          return Text(snapshot.data);
        } else {
          return Text('awaiting the future');
        }
      },
    );
    

    If you don't transform this Future into a String to be rendered, it will just be an Instance of Future.