Do not render any frames when just initializing Bindings (#39535)
This commit is contained in:
parent
e26be94e7a
commit
e2325600ea
@ -138,14 +138,13 @@ mixin RendererBinding on BindingBase, ServicesBinding, SchedulerBinding, Gesture
|
||||
|
||||
/// Creates a [RenderView] object to be the root of the
|
||||
/// [RenderObject] rendering tree, and initializes it so that it
|
||||
/// will be rendered when the engine is next ready to display a
|
||||
/// frame.
|
||||
/// will be rendered when the next frame is requested.
|
||||
///
|
||||
/// Called automatically when the binding is created.
|
||||
void initRenderView() {
|
||||
assert(renderView == null);
|
||||
renderView = RenderView(configuration: createViewConfiguration(), window: window);
|
||||
renderView.scheduleInitialFrame();
|
||||
renderView.prepareInitialFrame();
|
||||
}
|
||||
|
||||
/// The object that manages state about currently connected mice, for hover
|
||||
|
@ -74,7 +74,7 @@ class RenderView extends RenderObject with RenderObjectWithChildMixin<RenderBox>
|
||||
/// The configuration is initially set by the `configuration` argument
|
||||
/// passed to the constructor.
|
||||
///
|
||||
/// Always call [scheduleInitialFrame] before changing the configuration.
|
||||
/// Always call [prepareInitialFrame] before changing the configuration.
|
||||
set configuration(ViewConfiguration value) {
|
||||
assert(value != null);
|
||||
if (configuration == value)
|
||||
@ -110,16 +110,28 @@ class RenderView extends RenderObject with RenderObjectWithChildMixin<RenderBox>
|
||||
|
||||
/// Bootstrap the rendering pipeline by scheduling the first frame.
|
||||
///
|
||||
/// Deprecated. Call [prepareInitialFrame] followed by a call to
|
||||
/// [PipelineOwner.requestVisualUpdate] on [owner] instead.
|
||||
@Deprecated('Call prepareInitialFrame followed by owner.requestVisualUpdate() instead.')
|
||||
void scheduleInitialFrame() {
|
||||
prepareInitialFrame();
|
||||
owner.requestVisualUpdate();
|
||||
}
|
||||
|
||||
/// Bootstrap the rendering pipeline by preparing the first frame.
|
||||
///
|
||||
/// This should only be called once, and must be called before changing
|
||||
/// [configuration]. It is typically called immediately after calling the
|
||||
/// constructor.
|
||||
void scheduleInitialFrame() {
|
||||
///
|
||||
/// This does not actually schedule the first frame. Call
|
||||
/// [PipelineOwner.requestVisualUpdate] on [owner] to do that.
|
||||
void prepareInitialFrame() {
|
||||
assert(owner != null);
|
||||
assert(_rootTransform == null);
|
||||
scheduleInitialLayout();
|
||||
scheduleInitialPaint(_updateMatricesAndCreateNewRootLayer());
|
||||
assert(_rootTransform != null);
|
||||
owner.requestVisualUpdate();
|
||||
}
|
||||
|
||||
Matrix4 _rootTransform;
|
||||
|
@ -194,8 +194,6 @@ mixin SchedulerBinding on BindingBase, ServicesBinding {
|
||||
void initInstances() {
|
||||
super.initInstances();
|
||||
_instance = this;
|
||||
window.onBeginFrame = _handleBeginFrame;
|
||||
window.onDrawFrame = _handleDrawFrame;
|
||||
SystemChannels.lifecycle.setMessageHandler(_handleLifecycleMessage);
|
||||
readInitialLifecycleStateFromNativeWindow();
|
||||
|
||||
@ -656,6 +654,12 @@ mixin SchedulerBinding on BindingBase, ServicesBinding {
|
||||
scheduleFrame();
|
||||
}
|
||||
|
||||
@protected
|
||||
void ensureFrameCallbacksRegistered() {
|
||||
window.onBeginFrame ??= _handleBeginFrame;
|
||||
window.onDrawFrame ??= _handleDrawFrame;
|
||||
}
|
||||
|
||||
/// Schedules a new frame using [scheduleFrame] if this object is not
|
||||
/// currently producing a frame.
|
||||
///
|
||||
@ -717,6 +721,7 @@ mixin SchedulerBinding on BindingBase, ServicesBinding {
|
||||
debugPrintStack(label: 'scheduleFrame() called. Current phase is $schedulerPhase.');
|
||||
return true;
|
||||
}());
|
||||
ensureFrameCallbacksRegistered();
|
||||
window.scheduleFrame();
|
||||
_hasScheduledFrame = true;
|
||||
}
|
||||
|
@ -70,6 +70,7 @@ class TestServiceExtensionsBinding extends BindingBase
|
||||
bool frameScheduled = false;
|
||||
@override
|
||||
void scheduleFrame() {
|
||||
ensureFrameCallbacksRegistered();
|
||||
frameScheduled = true;
|
||||
}
|
||||
Future<void> doFrame() async {
|
||||
@ -126,7 +127,7 @@ void main() {
|
||||
final List<String> console = <String>[];
|
||||
|
||||
setUpAll(() async {
|
||||
binding = TestServiceExtensionsBinding();
|
||||
binding = TestServiceExtensionsBinding()..scheduleFrame();
|
||||
expect(binding.frameScheduled, isTrue);
|
||||
|
||||
// We need to test this service extension here because the result is true
|
||||
@ -140,7 +141,7 @@ void main() {
|
||||
firstFrameResult = await binding.testExtension('didSendFirstFrameRasterizedEvent', <String, String>{});
|
||||
expect(firstFrameResult, <String, String>{'enabled': 'false'});
|
||||
|
||||
await binding.doFrame(); // initial frame scheduled by creating the binding
|
||||
await binding.doFrame();
|
||||
|
||||
expect(binding.debugDidSendFirstFrameEvent, isTrue);
|
||||
firstFrameResult = await binding.testExtension('didSendFirstFrameEvent', <String, String>{});
|
||||
|
@ -48,7 +48,8 @@ void main() {
|
||||
final PipelineOwner pipelineOwner = PipelineOwner();
|
||||
renderView.attach(pipelineOwner);
|
||||
renderView.child = offscreen.root;
|
||||
renderView.scheduleInitialFrame();
|
||||
renderView.prepareInitialFrame();
|
||||
pipelineOwner.requestVisualUpdate();
|
||||
// Lay out the onscreen in the default binding
|
||||
layout(onscreen.root, phase: EnginePhase.paint);
|
||||
expect(onscreen.child.hasSize, isTrue);
|
||||
@ -77,7 +78,8 @@ void main() {
|
||||
final PipelineOwner pipelineOwner = PipelineOwner();
|
||||
renderView.attach(pipelineOwner);
|
||||
renderView.child = offscreen.root;
|
||||
renderView.scheduleInitialFrame();
|
||||
renderView.prepareInitialFrame();
|
||||
pipelineOwner.requestVisualUpdate();
|
||||
// Lay out the offscreen
|
||||
pipelineOwner.flushLayout();
|
||||
expect(offscreen.child.hasSize, isTrue);
|
||||
|
@ -0,0 +1,30 @@
|
||||
// Copyright 2019 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 'dart:ui' show window;
|
||||
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:flutter/widgets.dart';
|
||||
|
||||
void main() {
|
||||
test('Instantiating WidgetsFlutterBinding does neither schedule a frame nor register frame callbacks', () async {
|
||||
// Regression test for https://github.com/flutter/flutter/issues/39494.
|
||||
|
||||
// Preconditions.
|
||||
expect(WidgetsBinding.instance, isNull);
|
||||
expect(window.onBeginFrame, isNull);
|
||||
expect(window.onDrawFrame, isNull);
|
||||
|
||||
// Instantiation does nothing with regards to frame scheduling.
|
||||
final WidgetsFlutterBinding binding = WidgetsFlutterBinding.ensureInitialized();
|
||||
expect(binding.hasScheduledFrame, isFalse);
|
||||
expect(window.onBeginFrame, isNull);
|
||||
expect(window.onDrawFrame, isNull);
|
||||
|
||||
// Frame callbacks are registered lazily when a frame is scheduled.
|
||||
binding.scheduleFrame();
|
||||
expect(window.onBeginFrame, isNotNull);
|
||||
expect(window.onDrawFrame, isNotNull);
|
||||
});
|
||||
}
|
@ -23,7 +23,8 @@ class OffscreenRenderView extends RenderView {
|
||||
class OffscreenWidgetTree {
|
||||
OffscreenWidgetTree() {
|
||||
renderView.attach(pipelineOwner);
|
||||
renderView.scheduleInitialFrame();
|
||||
renderView.prepareInitialFrame();
|
||||
pipelineOwner.requestVisualUpdate();
|
||||
}
|
||||
|
||||
final RenderView renderView = OffscreenRenderView();
|
||||
|
@ -834,8 +834,6 @@ class AutomatedTestWidgetsFlutterBinding extends TestWidgetsFlutterBinding {
|
||||
@override
|
||||
void initInstances() {
|
||||
super.initInstances();
|
||||
window.onBeginFrame = null;
|
||||
window.onDrawFrame = null;
|
||||
_mockFlutterAssets();
|
||||
}
|
||||
|
||||
@ -978,6 +976,13 @@ class AutomatedTestWidgetsFlutterBinding extends TestWidgetsFlutterBinding {
|
||||
});
|
||||
}
|
||||
|
||||
@override
|
||||
void ensureFrameCallbacksRegistered() {
|
||||
// Leave Window alone, do nothing.
|
||||
assert(window.onDrawFrame == null);
|
||||
assert(window.onBeginFrame == null);
|
||||
}
|
||||
|
||||
@override
|
||||
void scheduleWarmUpFrame() {
|
||||
// We override the default version of this so that the application-startup warm-up frame
|
||||
@ -1361,7 +1366,7 @@ class LiveTestWidgetsFlutterBinding extends TestWidgetsFlutterBinding {
|
||||
onNeedPaint: _handleViewNeedsPaint,
|
||||
window: window,
|
||||
);
|
||||
renderView.scheduleInitialFrame();
|
||||
renderView.prepareInitialFrame();
|
||||
}
|
||||
|
||||
@override
|
||||
|
Loading…
x
Reference in New Issue
Block a user