Handling Asynchronous Dependencies in Flutter & Dart

Handling Asynchronous Dependencies in Flutter & Dart

In Flutter and Dart applications, it is common to encounter scenarios where a class depends on an asynchronous operation. For instance, a client or service may need to fetch data from a network, or a database may need to establish a connection before being utilized. There are various ways to handle these dependencies efficiently. This article will explore five different approaches to managing asynchronous dependencies in your Dart code.


For example, we have a base class for all examples like a:

abstract class ClientBase {
  abstract final FutureOr<Dependence> _dependence;

  FutureOr<Result> fetch() async {
    final dependence = await _dependence;
    /* Do some computation with dependence */
  }
}        



Passing the Dependency as a Parameter:

The first approach is to pass the dependency as a parameter to the method or constructor of your class. This lets you provide the dependency directly, ensuring it is available when needed. In the example code, the ClientPassed class receives the _dependence as a constructor parameter:

class ClientPassed extends ClientBase {
  ClientPassed(this._dependence);

  @override
  final Dependence _dependence;
}        



Preparing the Dependency in the Constructor:

In this approach, you initialize the dependency directly within the class's constructor. This ensures the dependency is ready for use after the class is instantiated. The ClientPrepared class demonstrates this method by initializing _dependence in the constructor:

class ClientPrepared extends ClientBase {
  ClientPrepared() : _dependence = $dependenceInitializer();

  @override
  final Future<Dependence> _dependence;
}
        



Using a Factory Method to Initialize the Dependency:

Another approach is to utilize a factory method to create an instance of the class with the dependency already initialized. This method involves awaiting the dependency initialization before returning the class instance. The ClientFactory class shows this technique with its initialize() method:

class ClientFactory extends ClientBase {
  static Future<ClientBase> initialize() async {
    final dependence = $dependenceInitializer();
    return ClientFactory._(dependence);
  }

  ClientFactory._(this._dependence);

  @override
  final Dependence _dependence;
}        



Lazy Initialization of the Dependency:

In some cases, it is more efficient to initialize the dependency only when it is needed for the first time. This can be achieved through lazy initialization. The ClientLazy class in the example code achieves this by using the late keyword:

class ClientLazy extends ClientBase {
  ClientLazy();

  @override
  late final Future<Dependence> _dependence = $dependenceInitializer();
}        



Lazy Initialization for Pre-Null Safety:

You can implement a similar approach using nullable types for projects that have not yet migrated to null safety. The ClientLazyNullable class demonstrates this method by checking if the _dependence is null before initializing it:

class ClientLazyNullable extends ClientBase {
  ClientLazyNullable();

  @override
  Future<Dependence> get _dependence => _$dependence ??= $dependenceInitializer();
  Future<Dependence>? _$dependence;
}        



Handling async dependencies in Flutter and Dart can be achieved in various ways. The five tips provided in this article – passing the dependency as a parameter, preparing the dependency in the constructor, using a factory static method, and using lazy initialization with or without null-safety – can help developers choose the most suitable approach for their specific use case.

Luqman Hakem

SWE | Flutter since 2017

2y

Actually this is a good read. Thanks!

To view or add a comment, sign in

More articles by Mike Matiunin

  • Business Logic Component [4 of 4]

    In this final article of the BLoC series, we will look at code examples and practical implementation of several popular…

  • Business Logic Component [3 of 4]

    In the third part of a series of articles about the bloc, we will analyze successful and unsuccessful decisions…

  • Harness the Power of Anonymous Functions in Dart

    Anonymous functions, also known as lambda expressions or closures, are an essential part of modern programming…

  • Business Logic Component [1 of 4]

    Introduction You can find the full original article here. We are starting a series of articles about Business Logic…

  • Business Logic Component [2 of 4]

    The second article is from a series of articles about BLoC. You can find the full article here.

  • Anti-patterns of error handling in dart

    This article will show common pitfalls you can make when handling exceptions and how to do it right. The article will…

  • Layer link

    Let’s take a look at how to create and display widgets that appear on top of other widgets and follow them when moved…

    1 Comment
  • ChangeNotifier selector

    Have you had a situation where you must select and rebuild the interface only to change specific fields of your…

Insights from the community

Others also viewed

Explore topics