Micheal Ross
Micheal Ross

Reputation: 211

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.

Upvotes: 4

Views: 5325

Answers (2)

Tobias Sid
Tobias Sid

Reputation: 118

you should use a FutureBuilder if you wanna render something that takes time (asynchronous)

FutureBuilder(
 future:_myRead,
 builder: (ctx,snapshot) {
  if(snapshot.connectionState == connectionState.waiting) {
   return // your waiting Widget Ex: CircularLoadingIndicator();
} else if (snapshot.hasData) { 
  return Text(snapshot.data.toString()); // toString() is just to be safe
} else { //probably an error occured
  return Text('Something went wrong ...');
}

Upvotes: 2

user7720975
user7720975

Reputation:

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.

Upvotes: 8

Related Questions