diff --git a/packages/flutter/lib/src/widgets/widget_inspector.dart b/packages/flutter/lib/src/widgets/widget_inspector.dart index 9270c9091f..6832e38b89 100644 --- a/packages/flutter/lib/src/widgets/widget_inspector.dart +++ b/packages/flutter/lib/src/widgets/widget_inspector.dart @@ -2068,7 +2068,7 @@ mixin WidgetInspectorService { } final Object? value = node.value; if (value is Element) { - final RenderObject? renderObject = value.renderObject; + final RenderObject? renderObject = _renderObjectOrNull(value); if (renderObject is RenderParagraph) { additionalPropertiesJson['textPreview'] = renderObject.text.toPlainText(); } @@ -2160,7 +2160,7 @@ mixin WidgetInspectorService { return null; } final RenderObject? renderObject = - object is Element ? object.renderObject : (object as RenderObject?); + object is Element ? _renderObjectOrNull(object) : (object as RenderObject?); if (renderObject == null || !renderObject.attached) { return null; } @@ -2224,7 +2224,7 @@ mixin WidgetInspectorService { InspectorSerializationDelegate delegate, ) { final Object? value = node.value; - final RenderObject? renderObject = value is Element ? value.renderObject : null; + final RenderObject? renderObject = value is Element ? _renderObjectOrNull(value) : null; if (renderObject == null) { return const {}; } @@ -2320,7 +2320,7 @@ mixin WidgetInspectorService { final Object? object = toObject(id); bool succeed = false; if (object != null && object is Element) { - final RenderObject? render = object.renderObject; + final RenderObject? render = _renderObjectOrNull(object); final ParentData? parentData = render?.parentData; if (parentData is FlexParentData) { parentData.fit = flexFit; @@ -2338,7 +2338,7 @@ mixin WidgetInspectorService { final dynamic object = toObject(id); bool succeed = false; if (object != null && object is Element) { - final RenderObject? render = object.renderObject; + final RenderObject? render = _renderObjectOrNull(object); final ParentData? parentData = render?.parentData; if (parentData is FlexParentData) { parentData.flex = factor; @@ -2362,7 +2362,7 @@ mixin WidgetInspectorService { final Object? object = toObject(id); bool succeed = false; if (object != null && object is Element) { - final RenderObject? render = object.renderObject; + final RenderObject? render = _renderObjectOrNull(object); if (render is RenderFlex) { render.mainAxisAlignment = mainAxisAlignment; render.crossAxisAlignment = crossAxisAlignment; @@ -2543,6 +2543,12 @@ mixin WidgetInspectorService { _clearStats(); _resetErrorCount(); } + + /// Safely get the render object of an [Element]. + /// + /// If the element is not yet mounted, the result will be null. + RenderObject? _renderObjectOrNull(Element element) => + element.mounted ? element.renderObject : null; } /// Accumulator for a count associated with a specific source location. diff --git a/packages/flutter/test/widgets/widget_inspector_test.dart b/packages/flutter/test/widgets/widget_inspector_test.dart index 94034afbe5..adfe355760 100644 --- a/packages/flutter/test/widgets/widget_inspector_test.dart +++ b/packages/flutter/test/widgets/widget_inspector_test.dart @@ -4837,6 +4837,32 @@ class _TestWidgetInspectorService extends TestWidgetInspectorService { expect(parentData['offsetY'], equals('293.0')); }); + testWidgets( + 'ext.flutter.inspector.getLayoutExplorerNode does not throw for unmounted widget', + (WidgetTester tester) async { + // Mount the Row widget. + await pumpWidgetForLayoutExplorer(tester); + + // Get the id of the Row widget. + final Element rowElement = tester.element(find.byType(Row)); + service.setSelection(rowElement, group); + final String id = service.toId(rowElement, group)!; + + // Unmount the Row widget. + await tester.pumpWidget(const Placeholder()); + + // Verify that the call to getLayoutExplorerNode for the Row widget + // does not throw an exception. + expect( + () => service.testExtension( + WidgetInspectorServiceExtensions.getLayoutExplorerNode.name, + {'id': id, 'groupName': group, 'subtreeDepth': '1'}, + ), + returnsNormally, + ); + }, + ); + testWidgets('ext.flutter.inspector.getLayoutExplorerNode for RenderBox with FlexParentData', ( WidgetTester tester, ) async {