Flutter Stream and Future: Understanding the Key Differences

Introduction

Modern app development requires asynchronous programming since it enables your app to carry out activities without delaying the main thread. Streams and futures are the two primary asynchronous task management tools offered by Flutter.

In that they both describe asynchronous processes that might or might not produce a value or an error, streams and futures are comparable. They are different in their behavior and execution, nevertheless.

We’ll examine when to use streams and futures in this article as well as take a deep dive into both of them.

What do Streams mean?

An order of asynchronous events is called a stream. Consider it to be a river that continuously emits events, such as data or faults. To manage data that comes in gradually over time, such as user input or network responses, streams are frequently utilized.

How does Flutter’s Streams function?

In Flutter, streams are represented by the Stream class. Streams can emit any type of value, including primitive types, custom classes, or even other streams. You can create a stream in Flutter by calling the Stream constructor and passing a function that defines the sequence of events.

Here is an illustration of how to make a stream that emits an integer sequence:

final myStream = Stream<int>.periodic(Duration(seconds: 1), (i) => i).take(5);

With the help of this code, a stream is produced that emits a value every second, ranging from 0 to 4. The stream can only emit the first 5 values when using the take() method.

Stream Operators in Common

Flutter streams have a number of built-in operators that let you control and alter the events that are broadcast. Here are a few of the most typical:

map()

Each event that the stream emits is transformed into a new value by the map() operator. Here is an illustration of how to change a stream of integers into a stream of strings using map():

final myStream = Stream<int>.fromIterable([1, 2, 3, 4, 5]);
final stringStream = myStream.map((i) => i.toString());


where()

The where() operator filters events from the stream according to a set of criteria. Here is an illustration of where() being used to filter an integer stream:

final myStream = Stream<int>.fromIterable([1, 2, 3, 4, 5]);
final evenStream = myStream.where((i) => i % 2 == 0);

By using this code, a new stream that exclusively emits even numbers is created.

take()

The stream’s ability to emit events is constrained by the take() operator. Here is an example of how to limit a stream to the first element using take().

skip()

The first n events that the stream emits are skipped by the skip() operator. Here is an illustration of how to use skip() to skip the first three events in an integer stream:

final myStream = Stream<int>.fromIterable([1, 2, 3, 4, 5]);
final skippedStream = myStream.skip(3);


fold()

The stream’s events are combined into a single value via the fold() operator. Here is an illustration showing how to use fold() to determine the sum of a stream of integers:

final myStream = Stream<int>.fromIterable([1, 2, 3, 4, 5]);
final sumStream = myStream.fold(0, (sum, i) => sum + i);

By running this code, a new stream is produced that emits the total of all the numbers in the initial stream.

How do futures work?

A value or mistake that may not yet be available is represented by a future. Futures are frequently used to manage lengthy processes, such as retrieving data from a distant server or reading a file from disk.

How are futures implemented in Flutter?

Future class in Flutter serves as a representation of futures. You can construct a future by invoking a function that returns one, and futures can emit any kind of value or error. Here is an illustration of building a future that, after a wait, resolves to a string:

Future<String> getDelayedString() async {
await Future.delayed(Duration(seconds: 1));
return 'Hello World';
}

This program constructs a future that, after a one-second delay, resolves to the string “Hello World.”

Standard Future Operators

Flutter futures also provide a number of built-in operators that let you modify and manage the value or error that the future emits. Here are a few of the most typical:

then()

You can deal with the value that the future emits by using the then() operator. Here is an illustration of how to print the outcome of a future using then():

getDelayedString().then((value) => print(value));


catchError()

You can respond to the error that the future emits by using the catchError() operator. Here is an illustration of how to print an error message using catchError():

getDelayedString()
.then((value) => print(value))
.catchError((error) => print('Error: $error'));

If the future resolves correctly, this code outputs “Hello World,” else it publishes “Error: [error message]”.

whenComplete()

Regardless of whether the future resolves successfully or fails, the whenComplete() operator enables you to execute a callback when it does. Here is an illustration of how to publish a message after a future completes using whenComplete():

getDelayedString().whenComplete(() => print('Future completed'));


When to use Futures vs. Streams

So when should you switch from using a future to a stream, and vice versa? The response is contingent upon the type of asynchronous action you’re managing.

When to use a stream

Like user input or network reactions, the data is being gathered over time.
Using stream operators, you wish to modify or adapt the events that were released.
Any errors that could happen during the stream must be handled.

When: Use a future

The data is a single value, and computing it could take a while, depending on whether you’re reading a file from disk or getting data from a remote server.
You are not required to deal with any potential errors that may arise.
The value that the operation emits does not require transformation or manipulation.

Streams are best suited to handle operations that return a single value after a possibly lengthy delay, whereas futures are best suited to handle operations that handle data that comes over time.

Conclusion

We have discussed the fundamentals of streams and futures in Flutter in this article. We’ve looked at how streams represent a timeline of events and how stream operators may be used to change and alter those events. We’ve also discussed how futures represent a value or error that may not yet be accessible and how to handle and modify those values using future operators.

You may build asynchronous code in Flutter that is more effective and efficient by knowing when to utilize streams and when to use futures. Streams and futures are effective tools that can help you accomplish your goals, whether you’re retrieving data from a distant server, responding to user input, or carrying out any other asynchronous action.

FAQs

  1. What is the difference between a stream and a future in Flutter? A stream represents a sequence of events over time, while a future represents a single value or error that may not be available yet.
  2. When should I use a stream in Flutter? You should use a stream when the data is arriving over time, like user input or network responses, and when you need to transform or manipulate the emitted events using stream operators.
  3. When should I use a future in Flutter? You should use a future when the data is a single value that may take a long time to compute, like fetching data from a remote server or reading a file from disk.
  4. Can I use stream and future together in Flutter? Yes, you can use stream and future together in Flutter. For example, you can use a future to fetch some data from a remote server, and then use a stream to process and display that data as it arrives.
  5. How can I handle errors in a stream or future in Flutter? You can handle errors in a stream or future by using operators like catchError() or by wrapping your code in a try-catch block.

Recent Posts

One Response

  1. I this not the opposite:

    “Streams are best suited to handle operations that return a single value after a possibly lengthy delay, whereas futures are best suited to handle operations that handle data that comes over time.”