Forbid calling findRenderObject on an unmounted element (#83962)
This commit is contained in:
parent
0100285e6f
commit
bcc8f083a2
@ -2056,7 +2056,8 @@ abstract class BuildContext {
|
||||
/// This method will only return a valid result after the build phase is
|
||||
/// complete. It is therefore not valid to call this from a build method.
|
||||
/// It should only be called from interaction event handlers (e.g.
|
||||
/// gesture callbacks) or layout or paint callbacks.
|
||||
/// gesture callbacks) or layout or paint callbacks. It is also not valid to
|
||||
/// call if [State.mounted] returns false.
|
||||
///
|
||||
/// If the render object is a [RenderBox], which is the common case, then the
|
||||
/// size of the render object can be obtained from the [size] getter. This is
|
||||
@ -3864,7 +3865,25 @@ abstract class Element extends DiagnosticableTree implements BuildContext {
|
||||
}
|
||||
|
||||
@override
|
||||
RenderObject? findRenderObject() => renderObject;
|
||||
RenderObject? findRenderObject() {
|
||||
assert(() {
|
||||
if (_lifecycleState != _ElementLifecycle.active) {
|
||||
throw FlutterError.fromParts(<DiagnosticsNode>[
|
||||
ErrorSummary('Cannot get renderObject of inactive element.'),
|
||||
ErrorDescription(
|
||||
'In order for an element to have a valid renderObject, it must be '
|
||||
'active, which means it is part of the tree.\n'
|
||||
'Instead, this element is in the $_lifecycleState state.\n'
|
||||
'If you called this method from a State object, consider guarding '
|
||||
'it with State.mounted.',
|
||||
),
|
||||
describeElement('The findRenderObject() method was called for the following element'),
|
||||
]);
|
||||
}
|
||||
return true;
|
||||
}());
|
||||
return renderObject;
|
||||
}
|
||||
|
||||
@override
|
||||
Size? get size {
|
||||
|
@ -2455,6 +2455,11 @@ class InspectorSelection {
|
||||
|
||||
Element? _currentElement;
|
||||
set currentElement(Element? element) {
|
||||
if (element?.debugIsDefunct == true) {
|
||||
_currentElement = null;
|
||||
_current = null;
|
||||
return;
|
||||
}
|
||||
if (currentElement != element) {
|
||||
_currentElement = element;
|
||||
_current = element!.findRenderObject();
|
||||
|
@ -1619,6 +1619,30 @@ void main() {
|
||||
await pumpWidget(Container());
|
||||
expect(states, <String>['deactivate', 'dispose']);
|
||||
});
|
||||
|
||||
testWidgets('Getting the render object of an unmounted element throws', (WidgetTester tester) async {
|
||||
await tester.pumpWidget(const _StatefulLeaf());
|
||||
final StatefulElement element = tester.element<StatefulElement>(find.byType(_StatefulLeaf));
|
||||
expect(element.state, isA<State<_StatefulLeaf>>());
|
||||
expect(element.widget, isA<_StatefulLeaf>());
|
||||
// Replace the widget tree to unmount the element.
|
||||
await tester.pumpWidget(Container());
|
||||
|
||||
expect(
|
||||
() => element.findRenderObject(),
|
||||
throwsA(isA<FlutterError>().having(
|
||||
(FlutterError error) => error.message,
|
||||
'message',
|
||||
equalsIgnoringHashCodes('''
|
||||
Cannot get renderObject of inactive element.
|
||||
In order for an element to have a valid renderObject, it must be active, which means it is part of the tree.
|
||||
Instead, this element is in the _ElementLifecycle.defunct state.
|
||||
If you called this method from a State object, consider guarding it with State.mounted.
|
||||
The findRenderObject() method was called for the following element:
|
||||
StatefulElement#00000(DEFUNCT)'''),
|
||||
)),
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
class _WidgetWithNoVisitChildren extends StatelessWidget {
|
||||
|
Loading…
x
Reference in New Issue
Block a user