Does your Flutter app need to perform some networking operations? Perhaps download some file or load an image? Maybe perform some heavy database queries or run some long operations? Well, Future, Async, and Await APIs are here to help you with such Asynchronous programming tasks.
Asynchronous Programming in an Android Application
In an Android application, whenever you run the app, a default process is created. Attached to that, a default main UI thread is created. Whenever you interact with your application, you do it with the help of the main UI thread. Within it, you can perform small operations such as user interaction, clicking a button or checking a checkbox, and maybe some small animations. These operations take considerably less amount of time.
However, when you want to perform some heavy operations such as downloading or uploading a file, in that case, parallel to the main thread, you create a separate "Worker thread." This thread can be used to perform long-running operations such as heavy database queries, loading an image, etc.
Asynchronous Programming in Dart
Android is multi-threaded, however Dart/Flutter is single-threaded. What it means is that in Dart/Flutter, you can only have the main UI thread, while you cannot have a separate "Worker thread." Now the question arises, how can we perform long-running operations like the ones mentioned previously in Flutter without making our app janky?
Solution
For performing Asynchronous programming in Flutter, you have Future, Async, and Await APIs with which you can perform heavy operations.
Defining Future
A future is defined in the same way as a function is in Dart, except instead of void, you use Future. If you wish to return a value from the Future, you must provide it with a type.
Future voidFuture() {}
Future<String> typedFuture() {}
Using Future
Let us define a dummy long-running operation that returns the Future type String.
Future<String> downloadFile(){
Future<String> result = Future.delay(Duration(second: 6)){
return "My file content";
}
return result;
}
Here we created a dummy function that will return a String after six seconds.
After six-second, the value of result variable will be assigned as a String instead of a Future.
A point to note here is that until the Future.delay() function return the String and assigns it to result, the datatype of result will still be a Future type.
Defining Async and Await
Let us define another function which uses the downloadFile() function.
void printFileContent(){
Future<String> fileContent = downloadFile();
print("The file content is -> $filecontent");
}
On running the function, the downloadFile() function just returns the Future object and not the valid String since it has yet to assign the String to the result variable, but it has been returned immediately instead of waiting for six seconds.
The fileContent variable, in this case, will be assigned an "Instance of Future" and not the actual value the function has to return.
To solve this problem, you should use await keyword while working with a Future function. The await keyword can only be used if we mark the function as async.
Using Await and Async
void printFileContent() _async_{
String fileContent = _await_ downloadFile();
print("The file content is -> $filecontent");
}
Doing this for the function means that unless you get a valid String result from the downloadFile() function, do not execute the next statement.
Also, since we are getting only a valid result and not expecting an instance of Future, we can reassign the datatype of fileContent as just String rather than Future.
This concept can also be expanded when working with live data from the internet or waiting for any operation to be performed Asynchronously.
Below mentioned are some more resources which can help you understand the concepts better:
Dart Futures - Flutter in Focus
Async/Await - Flutter in Focus
You can always visit the official Flutter docs
Top comments (0)