Do not render any frames when just initializing Bindings#39535
Do not render any frames when just initializing Bindings#39535goderbauer merged 5 commits intoflutter:masterfrom
Conversation
|
Could we make this less breaking by instead making a different My thinking is that here we're breaking some pretty old and established API, whereas the |
|
IOW - it seems strange to me to ensure that the widgets binding is initialized but to have to take an extra step to actually render widgets. Whereas I would expect that I could initialize the service bindings without necessarily rendering. |
|
Adding a new method seems more breaking to me as that will require people to change the API they are calling. This change as-is does not require any changes from most people who are using Flutter in the intended way. After initializing the bindings you always had to take an extra step (call runApp to attach your root widget) to actually render widgets. This PR is not changing this. This PR is just making sure that no frame gets rendered until this step has been taken. |
| debugPrintStack(label: 'scheduleFrame() called. Current phase is $schedulerPhase.'); | ||
| return true; | ||
| }()); | ||
| if (window.onBeginFrame == null) { |
There was a problem hiding this comment.
the omission of onDrawFrame on this line hurts
| bool frameScheduled = false; | ||
| @override | ||
| void scheduleFrame() { | ||
| if (ui.window.onBeginFrame == null) { |
There was a problem hiding this comment.
and the code duplication here hurts...
| renderView.child = offscreen.root; | ||
| renderView.scheduleInitialFrame(); | ||
| renderView.prepareInitialFrame(); | ||
| renderView.owner.requestVisualUpdate(); |
There was a problem hiding this comment.
why not just pipelineOwner.requestVisualUpdate?
| renderView.child = offscreen.root; | ||
| renderView.scheduleInitialFrame(); | ||
| renderView.prepareInitialFrame(); | ||
| renderView.owner.requestVisualUpdate(); |
| renderView.attach(pipelineOwner); | ||
| renderView.scheduleInitialFrame(); | ||
| renderView.prepareInitialFrame(); | ||
| renderView.owner.requestVisualUpdate(); |
| window.onBeginFrame = null; | ||
| window.onDrawFrame = null; | ||
| window.onBeginFrame = (Duration _) {}; | ||
| window.onDrawFrame = () {}; |
There was a problem hiding this comment.
maybe we should track if we've registered our callbacks separately from whether they're null, to avoid this kind of breakage...
Also, we could override registerFrameCallbacks here to enable the test harness and leave window entirely alone, thus avoiding this issue.
|
Comments addressed. PTAL @Hixie |
| debugPrintStack(label: 'scheduleFrame() called. Current phase is $schedulerPhase.'); | ||
| return true; | ||
| }()); | ||
| ensureFrameCallbacksRegistered(); |
There was a problem hiding this comment.
It feels a little bit hacky to me that we prevent the engine to achieve frame by not attaching listener, but i can't think of a better way, either.
|
|
||
| @override | ||
| void ensureFrameCallbacksRegistered() { | ||
| // Leave Window alone, do nothing. |
There was a problem hiding this comment.
maybe assert that window.onBeginFrame and window.onDrawFrame are null...
|
Hi - I'm currently on Flutter 1.12.13+hotfix.5 stable, and I'm still seeing a frame rendered when Is this expected? Any info gratefully received. Cheers! |
|
@shinyford see #39494 |
Thanks - yes, I found that. The suggested fix (#39494 (comment)) works for me; but I'll be more comfortable when it's properly part of the Flutter codebase. |
|
I have a massive black screen during initialization of the application. Any update on this? |
Description
Prior to this change, initializing the WidgetsFlutterBinding (e.g. via
WidgetsFlutterBinding.ensureInitialized) would register the frame callbacksonBeginFrameandonDrawFramewith the engine (this allowed to request the engine to render a frame whenever it wanted) and we would actively ask the engine to request the next frame viaWindow.scheduleFrame. In certain situations this caused the engine to request a frame (by callingonBeginFrame) when the framework wasn't ready to produce a meaningful frame (e. i. before the root widget was attached via a call torunApp). This would cause the framework to produce an empty frame, which in turn caused the engine to take down any splash screen and show a black empty screen.With this change, initializing the bindings does not register the frame callbacks with the engine so the engine has no chance of requesting a frame from the framework. Instead, the frame callbacks are lazily registered when the first frame is scheduled by the framework via
scheduleFrame. Additionally, initializing the bindings will no longer schedule a frame. The first frame gets scheduled when the root widget is attached and the framework is therefore ready to produce the first meaningful frame (or you can schedule a frame manually by callingscheduleFramewhenever you want).Related Issues
Fixes #39494.
Tests
I added the following tests:
Checklist
Before you create this PR confirm that it meets all requirements listed below by checking the relevant checkboxes (
[x]). This will ensure a smooth and quick review process.///).flutter analyze --flutter-repo) does not report any problems on my PR.Breaking Change
Does your PR require Flutter developers to manually update their apps to accommodate your change?