Repository navigation
Don't size or offset the Android platform view before it is laid out - #190895
Conversation
There was a problem hiding this comment.
Code Review
This pull request modifies RenderAndroidView._setOffset to only set the platform view offset when the render box is both attached and has a size, preventing crashes during route transitions when the box is not yet laid out. It also adds a regression test and updates FakeAndroidViewController to track offsets. Feedback on the changes points out that calling renderBox.dispose() while still attached to the render tree in the new test will trigger an assertion error in debug mode, and suggests clearing binding.renderView.child before disposal.
| renderBox.detach(); | ||
| layout(renderBox); | ||
| binding.pumpCompleteFrame(); | ||
|
|
||
| expect(viewController.offsets, <Offset>[Offset.zero]); | ||
|
|
||
| renderBox.dispose(); | ||
| }); |
There was a problem hiding this comment.
Calling renderBox.dispose() while the render box is still attached to the render tree (via layout(renderBox)) will throw an assertion error (Assertion failed: !attached) in debug mode. To prevent this, clear the child of renderView before disposing of the render box.
| renderBox.detach(); | |
| layout(renderBox); | |
| binding.pumpCompleteFrame(); | |
| expect(viewController.offsets, <Offset>[Offset.zero]); | |
| renderBox.dispose(); | |
| }); | |
| renderBox.detach(); | |
| layout(renderBox); | |
| binding.pumpCompleteFrame(); | |
| expect(viewController.offsets, <Offset>[Offset.zero]); | |
| binding.renderView.child = null; | |
| renderBox.dispose(); | |
| }); |
There was a problem hiding this comment.
There is no such assertion. RenderObject.dispose (rendering/object.dart:2065) asserts only !_debugDisposed and debugMaybeDispatchDisposed, and RenderAndroidView.dispose (rendering/platform_view.dart:252) clears the clip layer and the created-listener before calling super. The only !attached assert in the rendering library is object.dart:3922, which is on the semantics path.
The test directly above this one, markNeedsPaint does not get called on a disposed RO, already disposes a laid out RenderAndroidView while it is still renderView.child and pumps a further frame after. Leaving this as it is.
Piinks
left a comment
There was a problem hiding this comment.
Hey @wilyan09007 welcome, thanks for contributing!
Can you please restore and fill out the PR checklist from the template?
| // screen yet, and asking for one throws out of this frame callback, | ||
| // where nothing can catch it. | ||
| // See https://github.com/flutter/flutter/issues/190833. | ||
| if (attached && hasSize) { |
There was a problem hiding this comment.
if (_state == _PlatformViewState.resizing || !hasSize || size.isEmpty) {
return;
}
I think if controller is swapped while the render box is attached but not yet laid out, reading size.isEmpty throws an uncatchable RenderBox was not laid out inside this async method.
Adding !hasSize here prevents that crash. When layout completes, performResize() will invoke _sizePlatformView() with hasSize == true to perform the initial sizing.
Can you also add a test that verifies this?
|
Added the |
|
autosubmit label was removed for flutter/flutter/190895, because The base commit of the PR is older than 7 days and can not be merged. Please merge the latest changes from the main into this branch and resubmit the PR. |
|
autosubmit label was removed for flutter/flutter/190895, because - The status or check suite ci.yaml validation has failed. Please fix the issues identified (or deflake) before re-applying this label. |
RenderAndroidView._setOffset reschedules itself on every frame and only checks that the render object is not disposed and is still attached. A platform view mounted while a route transition is in flight is attached before the first layout of its route completes, so the callback asks a render box with no size for its position on screen, which throws. The read happens in a post frame callback, so nothing in the application can catch it. Guard the offset update with hasSize, the same way _handleGlobalPointerEvent guards the pointer path in this class. The callback keeps rescheduling itself while the box is unsized, so the offset is sent on the first frame after layout.
bf28cd3 to
43eab6e
Compare
Roll Flutter from c2437523d308 to 65c9a8dc60bc (195 revisions) flutter/flutter@c243752...65c9a8d 2026-08-22 [email protected] Roll ICU from d578f2e8b7bd to 8cc91d9b6ab9 (1 revision) (flutter/flutter#191542) 2026-08-22 [email protected] Roll Skia from 666a9b3d5cf0 to ad2106c0bb64 (3 revisions) (flutter/flutter#191527) 2026-08-22 [email protected] Roll Fuchsia Test Scripts from KaOq3EE4qJ9fnaaaK... to 0iCv10IlKfiilEBOU... (flutter/flutter#191524) 2026-08-22 [email protected] [flutter_tools] Add tests for negative lookahead regex in test runner and batch entrypoints (flutter/flutter#191438) 2026-08-22 [email protected] Roll Skia from 0c37868737fa to 666a9b3d5cf0 (2 revisions) (flutter/flutter#191518) 2026-08-21 [email protected] Revert "[input] Migrate fuchsia.ui.pointerinjector to TouchSource (#190855) (flutter/flutter#191509) 2026-08-21 [email protected] Fixes windows gallery benchmarks by forcing mobile layout (flutter/flutter#191507) 2026-08-21 [email protected] [flutter_tools] Restrict WebAssetServer source resolution to source map extensions (flutter/flutter#191501) 2026-08-21 [email protected] Roll Skia from f6900c5b8439 to 0c37868737fa (2 revisions) (flutter/flutter#191504) 2026-08-21 [email protected] Refactor `FlutterDevice.connect` and VM service discovery (flutter/flutter#191221) 2026-08-21 [email protected] [flutter_tools] Fix crash when migrating flow-style exclude lists in analysis_options.yaml (flutter/flutter#191269) 2026-08-21 [email protected] [rules] Add packages/flutter_tools/gradle/AGENTS.md rules (flutter/flutter#191486) 2026-08-21 [email protected] [flutter_tools] refactor CLI argument architecture with typed option descriptors and bundles (PoC) (flutter/flutter#191018) 2026-08-21 [email protected] tools: Extract Dart SDK to temp directory before moving to final location (flutter/flutter#191263) 2026-08-21 [email protected] [web] Move CanvasKit fragment shader classes to canvaskit/fragment_shader.dart (flutter/flutter#191451) 2026-08-21 [email protected] Roll Fuchsia Linux SDK from GCQlmt6h-esJsNubS... to ic6GjOSn-KN508XyK... (flutter/flutter#191485) 2026-08-21 [email protected] [Widget Preview] Isolate PageStorage scope in widget preview group expansion tile (flutter/flutter#191378) 2026-08-21 [email protected] [flutter_tools] Deprecate --build and --no-build flags on flutter run (flutter/flutter#191358) 2026-08-21 [email protected] Roll Skia from 70988bed1b3b to f6900c5b8439 (2 revisions) (flutter/flutter#191481) 2026-08-21 [email protected] Roll Packages from 1785501 to 252bb33 (6 revisions) (flutter/flutter#191480) 2026-08-21 [email protected] Roll Fuchsia Linux SDK from 20IJas24bZiNmCZTK... to GCQlmt6h-esJsNubS... (flutter/flutter#191415) 2026-08-21 [email protected] Roll Skia from 2ba6971bd0d1 to 70988bed1b3b (2 revisions) (flutter/flutter#191476) 2026-08-21 [email protected] Roll Skia from 1d5f72537ba6 to 2ba6971bd0d1 (2 revisions) (flutter/flutter#191473) 2026-08-21 [email protected] Roll Skia from 2c25efd2e369 to 1d5f72537ba6 (1 revision) (flutter/flutter#191472) 2026-08-21 [email protected] Roll Skia from 09b1b810850a to 2c25efd2e369 (9 revisions) (flutter/flutter#191470) 2026-08-21 [email protected] [Impeller] fix position of cached single glyph text shadows (flutter/flutter#191325) 2026-08-21 [email protected] Roll Skia from abdf8821f313 to 09b1b810850a (15 revisions) (flutter/flutter#191458) 2026-08-21 [email protected] Document that programmatic TextEditingController changes do not run input formatters (flutter/flutter#190166) 2026-08-21 [email protected] Adds new gallery benchmarks to windows (skia and impeller) (flutter/flutter#191454) 2026-08-21 [email protected] iOS: Deprecate FlutterEngine.isGpuDisabled (flutter/flutter#191393) 2026-08-21 [email protected] Revert: [web] Unskip decoration image lerp tests (flutter/flutter#191462) 2026-08-20 [email protected] android_hardware_smoke_test: Improve reliability (flutter/flutter#191374) 2026-08-20 [email protected] Don't size or offset the Android platform view before it is laid out (flutter/flutter#190895) 2026-08-20 [email protected] [iOS][add2app] Skip building SwiftPM plugins when generating CocoaPods artifacts (flutter/flutter#190736) 2026-08-20 [email protected] Optimize JSONMessageCodec UTF-8 conversion (flutter/flutter#190529) 2026-08-20 [email protected] [FML] Replace deprecated wstring_convert with Win32 APIs (flutter/flutter#191394) 2026-08-20 [email protected] SliverFillRemaining extends beyond viewport size when fillOverscroll is true (flutter/flutter#191236) 2026-08-20 [email protected] [flutter_tools] Update argParser usageLineLength when --wrap-column is passed (flutter/flutter#191264) 2026-08-20 [email protected] [flutter_tools] Fix UNC path resolution in depfile parsing on Windows (flutter/flutter#191265) 2026-08-20 [email protected] [web] Unskip decoration image lerp tests (flutter/flutter#191426) 2026-08-20 [email protected] Do not inject 'type' and 'method' into service extension responses (flutter/flutter#190946) 2026-08-20 [email protected] [flutter_tools] Fix crash in symbolize command on stream error (flutter/flutter#191273) 2026-08-20 [email protected] [flutter_tools] Prevent deletion of shared native asset hooks outputs as stale (flutter/flutter#191272) 2026-08-20 [email protected] [flutter_tools] Support package wildcard assets in app pubspec (flutter/flutter#191266) 2026-08-20 [email protected] Add SliverClipRect and SliverClipRRect (flutter/flutter#179003) 2026-08-20 [email protected] [flutter_tools] Implement Diagnostics extension slice and doctor integration (flutter/flutter#191162) ...
RenderAndroidViewreads its own size from two places that can run before the first layout: the postframe callback in
_setOffset, and_sizePlatformViewwhen the controller is swapped. A platform viewmounted while a route transition is in flight is attached before its route has laid out, so both throw
RenderBox was not laid outfrom a future that nothing can catch.Both now check
hasSizefirst, the same guard_handleGlobalPointerEventgot for the equivalent iOScrash in #83481. Nothing is lost by waiting: the offset callback reschedules itself every frame, and
performResizesizes the platform view as soon as layout gives it a size.One regression test per path in
packages/flutter/test/rendering/platform_view_test.dart, both builtthe way the existing
RenderUiKitViewtest for #83481 is, and both fail without the change.Fixes #190833
Pre-launch Checklist
///).