blob: 3a049ed75cfdd0f9311694881c14f2e4174de285 [file] [log] [blame]
// 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.
import 'framework.dart';
/// Provides non-leaking access to a [BuildContext].
///
/// A [BuildContext] is only valid if it is pointing to an active [Element].
/// 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.
///
/// 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(T 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;
}
}