Maxime Boissout
Maxime Boissout

Reputation: 77

Call asynchronous method which need the finish of another to complete

i don't realy know how to name this topik but this is my problem :

I have a class responsible for storing a fairly heavy object to initialize. On the first call to this class, I want my static object to be initialized, and then I can retrieve the object afterwards with other methods. My method to retrieve the object is asynchronous, and I want it to wait for the initialization to complete if ever called too soon.

However, I don't know how to wait for the initialization to finish... May be with a stream ?

Here's some code to illustrate where I'm at:

class Cartography{
  static Polygon? _bigObject;
  static bool _isLoading = false;

  Cartography(){
    _loadElement();
  }

  Future<void> _loadElement() async {
    if(_bigobject == null && _isLoading == false){
      _isLoading = true;
      _bigObject = await bigFunction();  // Loading object ...
      _isLoading = false;
    }
  }

  Future<Polygon> getPolygon() async {
    await ???? // Waiting the end of the initialisation if the bigObject is not yet initialized ...
    // TODO Ask to StackOverflow ...
    return _bigObject;
  }
}

Thank you for your help.

Upvotes: 0

Views: 46

Answers (1)

jamesdlin
jamesdlin

Reputation: 89926

You mostly could use just:

await _loadElement();

However, it would not behave correctly if _loadElement() can be called while an earlier call to _loadElement() is still in-flight. The second call would see that _isLoading is true and return immediately, and the second call would complete before _bigObject is set.

Instead of maintaining the bool _isLoaded flag, you instead can store the Future for the first call to _loadElement and make all subsequent calls await that same Future.

A pattern that I use is:

Future<void>? _loadingFuture;

Future<void> _loadElement() async {
  Future<void> internalLoad() async {
    _bigObject = await bigFunction();
  }

  return await (_loadingFuture ??= internalLoad());
}

Future<Polygon> getPolygon() async {
  await _loadElement();
  ...
}

Upvotes: 1

Related Questions