disposable_build_context.dart 2.49 KB
Newer Older
1 2 3 4
// Copyright 2014 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

5 6
// @dart = 2.8

7 8 9 10 11
import 'framework.dart';

/// Provides non-leaking access to a [BuildContext].
///
/// A [BuildContext] is only valid if it is pointing to an active [Element].
12 13 14
/// Once the [Element] is unmounted, the [BuildContext] should not be accessed
/// further. This class makes it possible for a [StatefulWidget] to share its
/// build context safely with other objects.
15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74
///
/// Creators of this object must guarantee the following:
///
///   1. They create this object at or after [State.initState] but before
///      [State.dispose]. In particular, do not attempt to create this from the
///      constructor of a state.
///   2. They call [dispose] from [State.dispose].
///
/// This object will not hold on to the [State] after disposal.
@optionalTypeArgs
class DisposableBuildContext<T extends State> {
  /// Creates an object that provides access to a [BuildContext] without leaking
  /// a [State].
  ///
  /// Creators must call [dispose] when the [State] is disposed.
  ///
  /// The [State] must not be null, and [State.mounted] must be true.
  DisposableBuildContext(this._state)
      : assert(_state != null),
        assert(_state.mounted, 'A DisposableBuildContext was given a BuildContext for an Element that is not mounted.');

  T _state;

  /// Provides safe access to the build context.
  ///
  /// If [dispose] has been called, will return null.
  ///
  /// Otherwise, asserts the [_state] is still mounted and returns its context.
  BuildContext get context {
    assert(_debugValidate());
    if (_state == null) {
      return null;
    }
    return _state.context;
  }

  /// Called from asserts or tests to determine whether this object is in a
  /// valid state.
  ///
  /// Always returns true, but will assert if [dispose] has not been called
  /// but the state this is tracking is unmounted.
  bool _debugValidate() {
    assert(
      _state == null || _state.mounted,
      'A DisposableBuildContext tried to access the BuildContext of a disposed '
      'State object. This can happen when the creator of this '
      'DisposableBuildContext fails to call dispose when it is disposed.',
    );
    return true;
  }


  /// Marks the [BuildContext] as disposed.
  ///
  /// Creators of this object must call [dispose] when their [Element] is
  /// unmounted, i.e. when [State.dispose] is called.
  void dispose() {
    _state = null;
  }
}