checkInstance<T extends BindingBase> method Null safety

  1. @protected
T checkInstance<T extends BindingBase>(
  1. T? instance
)

A method that shows a useful error message if the given binding instance is not initialized.

See initInstances for advice on using this method.

This method either returns the argument or throws an exception. In release mode it always returns the argument.

The type argument T should be the kind of binding mixin (e.g. SchedulerBinding) that is calling the method. It is used in error messages.

Implementation

@protected
static T checkInstance<T extends BindingBase>(T? instance) {
  assert(() {
    if (_debugInitializedType == null && instance == null) {
      throw FlutterError.fromParts(<DiagnosticsNode>[
        ErrorSummary('Binding has not yet been initialized.'),
        ErrorDescription('The "instance" getter on the $T binding mixin is only available once that binding has been initialized.'),
        ErrorHint(
          'Typically, this is done by calling "WidgetsFlutterBinding.ensureInitialized()" or "runApp()" (the '
          'latter calls the former). Typically this call is done in the "void main()" method. The "ensureInitialized" method '
          'is idempotent; calling it multiple times is not harmful. After calling that method, the "instance" getter will '
          'return the binding.',
        ),
        ErrorHint(
          'In a test, one can call "TestWidgetsFlutterBinding.ensureInitialized()" as the first line in the test\'s "main()" method '
          'to initialize the binding.',
        ),
        ErrorHint(
          'If $T is a custom binding mixin, there must also be a custom binding class, like WidgetsFlutterBinding, '
          'but that mixes in the selected binding, and that is the class that must be constructed before using the "instance" getter.',
        ),
      ]);
    }
    if (instance == null) {
      assert(_debugInitializedType == null);
      throw FlutterError.fromParts(<DiagnosticsNode>[
        ErrorSummary('Binding mixin instance is null but bindings are already initialized.'),
        ErrorDescription(
          'The "instance" property of the $T binding mixin was accessed, but that binding was not initialized when '
          'the "initInstances()" method was called.',
        ),
        ErrorHint(
          'This probably indicates that the $T mixin was not mixed into the class that was used to initialize the binding. '
          'If this is a custom binding mixin, there must also be a custom binding class, like WidgetsFlutterBinding, '
          'but that mixes in the selected binding. If this is a test binding, check that the binding being initialized '
          'is the same as the one into which the test binding is mixed.',
        ),
        ErrorHint(
          'It is also possible that $T does not implement "initInstances()" to assign a value to "instance". See the '
          'documentation of the BaseBinding class for more details.',
        ),
        ErrorHint(
          'The binding that was initialized was of the type "$_debugInitializedType". '
        ),
      ]);
    }
    try {
      assert(instance != null);
      if (instance._debugConstructed && _debugInitializedType == null) {
        throw FlutterError.fromParts(<DiagnosticsNode>[
          ErrorSummary('Binding initialized without calling initInstances.'),
          ErrorDescription('An instance of $T is non-null, but BindingBase.initInstances() has not yet been called.'),
          ErrorHint(
            'This could happen because a binding mixin was somehow used outside of the normal binding mechanisms, or because '
            'the binding\'s initInstances() method did not call "super.initInstances()".',
          ),
          ErrorHint(
            'This could also happen if some code was invoked that used the binding while the binding was initializing, '
            'for example if the "initInstances" method invokes a callback. Bindings should not invoke callbacks before '
            '"initInstances" has completed.',
          ),
        ]);
      }
      if (!instance._debugConstructed) {
        // The state of _debugInitializedType doesn't matter in this failure mode.
        throw FlutterError.fromParts(<DiagnosticsNode>[
          ErrorSummary('Binding did not complete initialization.'),
          ErrorDescription('An instance of $T is non-null, but the BindingBase() constructor has not yet been called.'),
          ErrorHint(
            'This could also happen if some code was invoked that used the binding while the binding was initializing, '
            "for example if the binding's constructor itself invokes a callback. Bindings should not invoke callbacks "
            'before "initInstances" has completed.',
          ),
        ]);
      }
    } on NoSuchMethodError {
      throw FlutterError.fromParts(<DiagnosticsNode>[
        ErrorSummary('Binding does not extend BindingBase'),
        ErrorDescription('An instance of $T was created but the BindingBase constructor was not called.'),
        ErrorHint(
          'This could happen because the binding was implemented using "implements" rather than "extends" or "with". '
          'Concrete binding classes must extend or mix in BindingBase.',
        ),
      ]);
    }
    return true;
  }());
  return instance!;
}