In this course, we will explain in detail how to create and output Future
in Flutter. Future
is a core concept in Dart’s asynchronous programming, representing an object that returns a value or error when an asynchronous task is completed. This allows us to perform time-consuming tasks without blocking the UI.
1. What is Future?
Future
is an object that represents a future result in asynchronous programming, allowing you to wait for the asynchronous task to complete and receive the result. For example, when fetching data through an HTTP request, you can proceed with other UI tasks without waiting for the request to finish.
1.1 States of Future
- Pending: State where the task has not yet completed.
- Completed: State where the task has completed and returned a result.
- Error: State where an error occurred during the task.
2. Creating a Future
There are two main ways to create a Future
. The first is to use built-in methods, and the second is to create it through custom functions.
2.1 Using Built-in Methods
You can create a Future
object that completes after a certain time using the Future.delayed
method. The following is an example that returns a message after 2 seconds.
Future fetchData() {
return Future.delayed(Duration(seconds: 2), () {
return 'Data loading complete';
});
}
2.2 Creating Custom Functions
You can directly create a function that returns a Future
to handle database or API requests. For example, let’s create a function to fetch user information from an API.
Future fetchUser(int userId) async {
final response = await http.get('https://api.example.com/user/$userId');
if (response.statusCode == 200) {
return User.fromJson(json.decode(response.body));
} else {
throw Exception('Failed to load user');
}
}
3. Outputting Futures
Now, let’s look at how to output the values of the Future
object we created in a Flutter app. To do this, we use the FutureBuilder
widget. The FutureBuilder
dynamically updates the UI based on the state of the Future
.
3.1 Using FutureBuilder
To use FutureBuilder
, you need to define the future
and builder
parameters. You specify the Future
object that performs the asynchronous task in future
, and define the function that builds the UI based on the state of the asynchronous task in builder
.
class UserProfile extends StatelessWidget {
final int userId;
UserProfile(this.userId);
@override
Widget build(BuildContext context) {
return FutureBuilder(
future: fetchUser(userId),
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.waiting) {
return CircularProgressIndicator();
} else if (snapshot.hasError) {
return Text('Error: ${snapshot.error}');
} else {
return Text('User Name: ${snapshot.data.name}');
}
},
);
}
}
3.2 Exception Handling
Since errors may occur during asynchronous tasks, it’s important to handle errors in FutureBuilder
using snapshot.hasError
. Proper exception handling can provide clear feedback to users.
4. Complete Code Example
Based on what we have learned so far, let’s look at a complete example. This example is a Flutter app that calls an API to fetch user information and displays it on the screen.
import 'package:flutter/material.dart';
import 'dart:convert';
import 'package:http/http.dart' as http;
class User {
final String name;
User({required this.name});
factory User.fromJson(Map json) {
return User(name: json['name']);
}
}
Future fetchUser(int userId) async {
final response = await http.get('https://api.example.com/user/$userId');
if (response.statusCode == 200) {
return User.fromJson(json.decode(response.body));
} else {
throw Exception('Failed to load user');
}
}
class UserProfile extends StatelessWidget {
final int userId;
UserProfile(this.userId);
@override
Widget build(BuildContext context) {
return FutureBuilder(
future: fetchUser(userId),
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.waiting) {
return CircularProgressIndicator();
} else if (snapshot.hasError) {
return Text('Error: ${snapshot.error}');
} else {
return Text('User Name: ${snapshot.data.name}');
}
},
);
}
}
void main() => runApp(MaterialApp(home: Scaffold(body: UserProfile(1))));
5. Conclusion
In this course, we learned how to create Future
in Flutter and efficiently handle asynchronous operations using it. The UI composed with FutureBuilder
can change dynamically based on data loading states, which is very useful. These asynchronous programming techniques greatly help improve user experience even in complex apps.
Stream
and async/await
.