Skip to main content

Observer Pattern: The Hidden Magic Behind Flutter State Management

When I first started learning state management in Flutter, it honestly felt like magic. I'd change one variable, call setState , and the screen would just… update. Later I met ValueNotifier and ValueListenableBuilder , and it got even stranger — now only one widget would rebuild while everything around it stayed perfectly still. I hadn't written any code to watch for changes. I hadn't wired anything up. It just worked. And anything that "just works" without me understanding why makes me a little uncomfortable. So I did what any curious developer does: I went down the rabbit hole. I wanted to know how a value "knows" when to tell the UI to rebuild. Who is listening? How does the change travel from my variable to the pixels on screen? That question led me to something much bigger than Flutter — a classic software design pattern called the Observer pattern . Once I understood it, the magic didn't disappear. It just turned into some...

Multithreading in flutter!

Now, some of you might be wondering—Wait, what? Multithreading in Flutter? Yes, that’s correct! Flutter is fully capable of handling multithreading. While Flutter primarily relies on the main thread for rendering and performing other tasks, modern mobile processors come equipped with multiple threads, so why not take advantage of them?

Some of you may be asking, why do we even need additional threads when the main thread can handle most tasks just fine? And I agree, the main thread can indeed manage a lot of work. However, when it comes to performance-heavy operations like complex computations or intensive data processing, you might notice that your app's UI starts to freeze, or you experience frame drops. This is where multithreading becomes the ideal solution, helping to offload these tasks and keep your UI responsive.

Isolates

Before diving into multithreading in Flutter, it's essential to first understand Isolates. Unlike traditional multithreading, where threads share memory and can lead to issues like race conditions and deadlocks, Flutter takes a different approach to concurrency using Isolates.

Isolates are independent execution units that run code in parallel to the main application. Each isolate operates in its own memory space, with its own event loop, completely isolated from other isolates and the main thread. This design ensures that there is no shared memory between isolates, which effectively eliminates many common concurrency problems that are prevalent in traditional multithreading, such as race conditions, deadlocks, and resource contention.

The key to communication between isolates is message passing. Since isolates don't share memory, they rely on sending and receiving messages through ports (SendPort and ReceivePort) to coordinate tasks. This message-passing architecture ensures that isolates can perform concurrent tasks without affecting each other's state, making it easier to write error-free concurrent code.

import 'dart:isolate';

void backgroundTask(SendPort sendPort) {
int result = 0;
for (int i = 0; i < 1000000000; i++) {
result += i;
}
sendPort.send(result);
}

void main() async {
  ReceivePort receivePort = ReceivePort();

await Isolate.spawn(backgroundTask, receivePort.sendPort);

receivePort.listen((result) {
print(
result);
},
 );
}

Compute Function

The Compute function, provided by the flutter/foundation.dart package, is a utility that allows you to offload long-running, computationally intensive tasks to a background Isolate. Rather than executing these tasks on the main UI thread, Compute spawns a new Isolate, ensuring that the UI remains smooth and responsive during the process. Once the background task is completed, the result is passed back to the main thread.

For resource-heavy operations such as data processing, JSON parsing, or file I/O, you can use the Compute function to handle these tasks in the background. It creates an Isolate specifically for the task, preventing the main thread from being blocked. The background isolate performs the computation independently, and once it finishes, the result is communicated back to the main isolate through message passing.

In essence, the Compute function leverages Isolates to efficiently manage heavy workloads, maintaining the performance and responsiveness of your app.

import 'package:flutter/foundation.dart'; 

int backgroundTask(int value) {
int result = 0;
for (int i = 0; i < value; i++) {
result += i;
}
return result;
}

void main() async {
int result = await compute(backgroundTask, 1000000000);

print(result);
}

Flutter's compute function and isolates provide a powerful and efficient way to handle heavy computational tasks without compromising the performance of your app's user interface. By offloading resource-intensive operations, you can keep the main thread unblocked and ensure a smooth, responsive user experience. 

In my next blog post, I will try to demonstrate a practical example of implementing multithreading in Flutter, showcasing how to efficiently manage both UI updates and background tasks simultaneously.

Comments

Popular posts from this blog

Keep Your Promises: The Liskov Substitution Principle Made Simple

If you're learning clean code, you'll keep running into the "SOLID" principles. The L stands for the Liskov Substitution Principle (LSP) — a scary name for a genuinely simple idea. This guide starts from zero, so no prior knowledge is needed. What it is The Liskov Substitution Principle says: If something is supposed to work like a certain type, then any "version" of that type must be able to take its place without causing problems. That's the whole thing. If you call something a Doctor , it has to actually behave like a doctor everywhere a doctor is expected. If you call something an ApiClient , it has to behave like one everywhere. Break that, and your program fails — usually later, in a confusing way. The principle is named after Barbara Liskov, a computer scientist who described it back in 1987. But you don't need the academic version to use it well. First, what does "substitute" mean? This is the word that makes the whole pr...

Understanding BuildContext in Flutter!

As a Flutter developer, you might have encountered the term BuildContext early in your journey. Despite its importance, many developers struggle to grasp its full significance. Today, we’re going to dive into what BuildContext is, what it does, and why it’s crucial for running your Flutter app. What is BuildContext In both stateless and stateful widgets, when you override the build method, it takes BuildContext context as a parameter. This context is provided by the Flutter framework. Here’s a simple example to illustrate: Widget build(BuildContext context) { return OutlinedButton( onPressed: () async { await Future< void >.delayed( const Duration(seconds: 1 )); if (context.mounted) { Navigator.of(context).pop(); } }, child: const Text( 'Delayed pop' ), ); } BuildContext do a simple task, track all of your widget location. In flutter, it all about widgets. Everything is build on a collection of widgets. Some widgets are parent w...

Observer Pattern: The Hidden Magic Behind Flutter State Management

When I first started learning state management in Flutter, it honestly felt like magic. I'd change one variable, call setState , and the screen would just… update. Later I met ValueNotifier and ValueListenableBuilder , and it got even stranger — now only one widget would rebuild while everything around it stayed perfectly still. I hadn't written any code to watch for changes. I hadn't wired anything up. It just worked. And anything that "just works" without me understanding why makes me a little uncomfortable. So I did what any curious developer does: I went down the rabbit hole. I wanted to know how a value "knows" when to tell the UI to rebuild. Who is listening? How does the change travel from my variable to the pixels on screen? That question led me to something much bigger than Flutter — a classic software design pattern called the Observer pattern . Once I understood it, the magic didn't disappear. It just turned into some...