How to create two threads in Dart in the context of Flutter?
sobes.tech AI
Answer from AI
To create independent execution threads in Dart/Flutter, Isolates are used. They represent separate tasks with their own dedicated memory space, preventing issues with concurrent data access and blocking the main thread (UI thread).
There are several ways to create and interact with isolates:
-
Isolate.spawn(): The lowest-level method for creating an isolate. It requires passing a top-level function or static class method to execute in the new isolate and a port for message exchange.import 'dart:isolate'; // Function to run in the isolate void isolateEntry(SendPort sendPort) { // Perform some long operation int result = 0; for (int i = 0; i < 1000000000; i++) { result += i; } // Send the result back to the main isolate sendPort.send(result); } void main() async { ReceivePort receivePort = ReceivePort(); // Create a new isolate Isolate isolate = await Isolate.spawn(isolateEntry, receivePort.sendPort); // Listen for messages from the isolate receivePort.listen((message) { print('Result from isolate: $message'); // Kill the isolate after receiving the message isolate.kill(); }); print('Main thread continues to work...'); } -
compute(): A simplified function from theflutter/foundationpackage that internally usesIsolate.spawn(). Ideal for simple background tasks that do not require complex interaction with the isolate.import 'package:flutter/foundation.dart'; // Function to run with compute int heavyComputation(int limit) { int result = 0; for (int i = 0; i < limit; i++) { result += i; } return result; } void main() async { print('Starting heavy computations in background...'); // Run the function in a separate isolate int result = await compute(heavyComputation, 1000000000); print('Computation result: $result'); print('Main thread continues after computations.'); } -
Isolate.spawnUri(): Used to run code from a separate Dart file in a new isolate.
Interaction between isolates:
Isolates communicate only through message passing via SendPort and ReceivePort instances. These are atomic operations that do not require locks or other synchronization mechanisms.
SendPort: Used to send messages from one isolate to another.ReceivePort: Used to listen for incoming messages.
When passing objects between isolates, they must be "transferable," which includes:
- Primitive data types (int, double, String, bool)
- Lists and maps containing transferable types
- Certain Flutter-specific types that can be serialized
Non-transferable objects will be copied, and subsequent changes in one isolate will not reflect in the other.
Key points:
- Isolates cannot directly access each other's memory.
- Isolates do not have access to shared state, including variables, classes, and widgets of the main isolate (UI thread).
- Communication between isolates is asynchronous.
- When working with isolates in Flutter, it is important to manage their lifecycle properly (e.g., using
isolate.kill()when necessary).
Using isolates allows performing long-running or resource-intensive operations in the background, preventing UI freezing and ensuring smooth app operation.