Flutter&Dart Callback to synchronization

foreword

How to convert a Callback callback into a Future synchronization method (Callback to Future), which can be used with async / await?

Personally, I think this is a very common phenomenon. I don’t know why. Many people didn’t mention this scene when explaining the usage of Future.

course

  • Why should I convert Callback to Future method?
    • As you all know, when Flutter loads a page, there is a rendering process. When the rendering is not completed, you will display some View operations, and an error will be reported, for example: loading the loading pop-up window
    • The solution may be known to everyone, do a delay operation in the Lifecycle.initState / iniState life cycle or use WidgetsBinding
//Delay operation
await Future.delayed(Duration(milliseconds: 200));
//The following popup can be loaded

//Using WidgetsBinding
WidgetsBinding.instance.addPostFrameCallback((timeStamp) {
    //Popups can be loaded here
});
  • Of course, using WidgetsBinding is more reliable and accurate, but this Callback makes me very convenient, and the name is too long and I can't remember it very well, so I need to encapsulate it
  • Encapsulate WidgetsBinding
    • Egg cone, how to package this thing?
class ViewUtil {
  /// interface initialization complete
  static Future<Void> initFinish() async {
    WidgetsBinding.instance.addPostFrameCallback((timeStamp) {
      
    });
  }
}
  • First I thought: Future.delayed()
    • Go in and look at his source code
    • There is a play, you can see that it obviously contains a Callback callback in Timer, but it was finally converted into the Future method
factory Future.delayed(Duration duration, [FutureOr<T> computation()?]) {
    if (computation == null && !typeAcceptsNull<T>()) {
        throw ArgumentError.value(
            null, "computation", "The type parameter is not nullable");
    }
    _Future<T> result = new _Future<T>();
    new Timer(duration, () {
        if (computation == null) {
            result._complete(null as T);
        } else {
            try {
                result._complete(computation());
            } catch (e, s) {
                _completeWithErrorCallback(result, e, s);
            }
        }
    });
    return result;
}
  • under analysis

    • The first is to instantiate a _Future() object, and then return the _Future() object
    • It can be seen that the bottom of the method directly returns the object. It is conceivable that this place must have been in a blocking state, waiting for a condition to end this blocking state.
    • Then after the Timer's delay time expires, the _complete() method is used in its callback. This method should end the blocking state of the _Future() object, and then return the _Future() object, and this method also ends span
  • It's not that simple, I'll just copy this out.

  • This _Future class is a private method. In the future_impl.dart file, copy this file out and put it in the same package as our tool class file.

    • Then. . .

  • This bunch of errors, playing with wool, must be the way I opened it wrong

    • Is it necessary to solve these errors one by one? If it's so troublesome, it's still doing wool!

  • Is my search posture wrong? Let's search again
    • I go, and it automatically prompts me: dart callback to future, is it so magical? try it

solution

  • Record the writing method of Callback to Future, it is very simple, just use the Completer class
class ViewUtil {
  /// interface initialization complete
  static Future<Void> initFinish() async {
    Completer<Void> completer = Completer();

    WidgetsBinding.instance.addPostFrameCallback((timeStamp) {
      completer.complete();
    });

    return completer.future;
  }
}
  • use
    • It is much easier to use in an instant
void _init() async {
    await ViewUtil.initFinish();
    /// The loading popup can be used below
}

illustrate

  • The generics of Future and Completer should be consistent
    • For example, if they are all String s, you can add the corresponding content in the complete() method, and when await accepts this method, you can get the value entered in the complete() method.
class ViewUtil {
    /// interface initialization complete
    static Future<String> initFinish() async {
        Completer<String> completer = Completer();

        WidgetsBinding.instance.addPostFrameCallback((timeStamp) {
            completer.complete("have a test...");
        });

        return completer.future;
    }
}


void _init() async {
    var s = await ViewUtil.initFinish();
    print(s);
}

Tags: Flutter

Posted by nootkan on Tue, 10 May 2022 04:46:13 +0300