Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Sign in
Toggle navigation
F
Front-End
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
abdullh.alsoleman
Front-End
Commits
4c64b715
Unverified
Commit
4c64b715
authored
Nov 22, 2019
by
Todd Volkert
Committed by
GitHub
Nov 22, 2019
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Revert "Add option to delay rendering the first frame (#45135)" (#45385)
This reverts commit
d285b884
.
parent
cb35c88b
Changes
4
Hide whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
30 additions
and
165 deletions
+30
-165
binding.dart
packages/flutter/lib/src/rendering/binding.dart
+2
-52
binding.dart
packages/flutter/lib/src/widgets/binding.dart
+26
-26
localizations.dart
packages/flutter/lib/src/widgets/localizations.dart
+2
-3
binding_deferred_first_frame_test.dart
...utter/test/widgets/binding_deferred_first_frame_test.dart
+0
-84
No files found.
packages/flutter/lib/src/rendering/binding.dart
View file @
4c64b715
...
...
@@ -283,53 +283,6 @@ mixin RendererBinding on BindingBase, ServicesBinding, SchedulerBinding, Gesture
drawFrame
();
}
int
_firstFrameDeferredCount
=
0
;
bool
_firstFrameSent
=
false
;
/// Whether frames produced by [drawFrame] are sent to the engine.
///
/// If false the framework will do all the work to produce a frame,
/// but the frame is never send to the engine to actually appear on screen.
///
/// See also:
///
/// * [deferFirstFrame], which defers when the first frame is send to the
/// engine.
bool
get
sendFramesToEngine
=>
_firstFrameSent
||
_firstFrameDeferredCount
==
0
;
/// Tell the framework to not send the first frames to the engine until there
/// is a corresponding call to [allowFirstFrame].
///
/// Call this to perform asynchronous initialisation work before the first
/// frame is rendered (which takes down the splash screen). The framework
/// will still do all the work to produce frames, but those frames are never
/// send to the engine and will not appear on screen.
///
/// Calling this has no effect after the first frame has been send to the
/// engine.
void
deferFirstFrame
()
{
assert
(
_firstFrameDeferredCount
>=
0
);
_firstFrameDeferredCount
+=
1
;
}
/// Called after [deferFirstFrame] to tell the framework that it is ok to
/// send the first frame to the engine now.
///
/// For best performance, this method should only be called while the
/// [schedulerPhase] is [SchedulerPhase.idle].
///
/// This method may only be called once for each corresponding call
/// to [deferFirstFrame].
void
allowFirstFrame
()
{
assert
(
_firstFrameDeferredCount
>
0
);
_firstFrameDeferredCount
-=
1
;
// Always schedule a warm up frame even if the deferral count is not down to
// zero yet since the removal of a deferral may uncover new deferrals that
// are lower in the widget tree.
if
(!
_firstFrameSent
)
scheduleWarmUpFrame
();
}
/// Pump the rendering pipeline to generate a frame.
///
/// This method is called by [handleDrawFrame], which itself is called
...
...
@@ -391,11 +344,8 @@ mixin RendererBinding on BindingBase, ServicesBinding, SchedulerBinding, Gesture
pipelineOwner
.
flushLayout
();
pipelineOwner
.
flushCompositingBits
();
pipelineOwner
.
flushPaint
();
if
(
sendFramesToEngine
)
{
renderView
.
compositeFrame
();
// this sends the bits to the GPU
pipelineOwner
.
flushSemantics
();
// this also sends the semantics to the OS.
_firstFrameSent
=
true
;
}
renderView
.
compositeFrame
();
// this sends the bits to the GPU
pipelineOwner
.
flushSemantics
();
// this also sends the semantics to the OS.
}
@override
...
...
packages/flutter/lib/src/widgets/binding.dart
View file @
4c64b715
...
...
@@ -572,6 +572,9 @@ mixin WidgetsBinding on BindingBase, ServicesBinding, SchedulerBinding, GestureB
}
bool
_needToReportFirstFrame
=
true
;
int
_deferFirstFrameReportCount
=
0
;
bool
get
_reportFirstFrame
=>
_deferFirstFrameReportCount
==
0
;
final
Completer
<
void
>
_firstFrameCompleter
=
Completer
<
void
>();
...
...
@@ -597,6 +600,11 @@ mixin WidgetsBinding on BindingBase, ServicesBinding, SchedulerBinding, GestureB
/// Whether the first frame has finished building.
///
/// Only useful in profile and debug builds; in release builds, this always
/// return false. This can be deferred using [deferFirstFrameReport] and
/// [allowFirstFrameReport]. The value is set at the end of the call to
/// [drawFrame].
///
/// This value can also be obtained over the VM service protocol as
/// `ext.flutter.didSendFirstFrameEvent`.
///
...
...
@@ -608,30 +616,27 @@ mixin WidgetsBinding on BindingBase, ServicesBinding, SchedulerBinding, GestureB
/// Tell the framework not to report the frame it is building as a "useful"
/// first frame until there is a corresponding call to [allowFirstFrameReport].
///
/// Deprecated. Use [deferFirstFrame]/[allowFirstFrame] to delay rendering the
/// first frame.
@Deprecated
(
'Use deferFirstFrame/allowFirstFrame to delay rendering the first frame. '
'This feature was deprecated after v1.12.4.'
)
/// This is used by [WidgetsApp] to avoid reporting frames that aren't useful
/// during startup as the "first frame".
void
deferFirstFrameReport
()
{
if
(!
kReleaseMode
)
{
deferFirstFrame
();
assert
(
_deferFirstFrameReportCount
>=
0
);
_deferFirstFrameReportCount
+=
1
;
}
}
/// When called after [deferFirstFrameReport]: tell the framework to report
/// the frame it is building as a "useful" first frame.
///
/// Deprecated. Use [deferFirstFrame]/[allowFirstFrame] to delay rendering the
/// first frame.
@Deprecated
(
'Use deferFirstFrame/allowFirstFrame to delay rendering the first frame. '
'This feature was deprecated after v1.12.4.'
)
/// This method may only be called once for each corresponding call
/// to [deferFirstFrameReport].
///
/// This is used by [WidgetsApp] to report when the first useful frame is
/// painted.
void
allowFirstFrameReport
()
{
if
(!
kReleaseMode
)
{
allowFirstFrame
();
assert
(
_deferFirstFrameReportCount
>=
1
);
_deferFirstFrameReportCount
-=
1
;
}
}
...
...
@@ -748,23 +753,18 @@ mixin WidgetsBinding on BindingBase, ServicesBinding, SchedulerBinding, GestureB
return
true
;
}());
TimingsCallback
firstFrameCallback
;
if
(
_needToReportFirstFrame
)
{
if
(
_needToReportFirstFrame
&&
_reportFirstFrame
)
{
assert
(!
_firstFrameCompleter
.
isCompleted
);
TimingsCallback
firstFrameCallback
;
firstFrameCallback
=
(
List
<
FrameTiming
>
timings
)
{
assert
(
sendFramesToEngine
);
if
(!
kReleaseMode
)
{
developer
.
Timeline
.
instantSync
(
'Rasterized first useful frame'
);
developer
.
postEvent
(
'Flutter.FirstFrame'
,
<
String
,
dynamic
>{});
}
SchedulerBinding
.
instance
.
removeTimingsCallback
(
firstFrameCallback
);
firstFrameCallback
=
null
;
_firstFrameCompleter
.
complete
();
};
// Callback is only invoked when [Window.render] is called. When
// [sendFramesToEngine] is set to false during the frame, it will not
// be called and we need to remove the callback (see below).
SchedulerBinding
.
instance
.
addTimingsCallback
(
firstFrameCallback
);
}
...
...
@@ -780,14 +780,11 @@ mixin WidgetsBinding on BindingBase, ServicesBinding, SchedulerBinding, GestureB
}());
}
if
(!
kReleaseMode
)
{
if
(
_needToReportFirstFrame
&&
sendFramesToEngin
e
)
{
if
(
_needToReportFirstFrame
&&
_reportFirstFram
e
)
{
developer
.
Timeline
.
instantSync
(
'Widgets built first useful frame'
);
}
}
_needToReportFirstFrame
=
false
;
if
(
firstFrameCallback
!=
null
&&
!
sendFramesToEngine
)
{
SchedulerBinding
.
instance
.
removeTimingsCallback
(
firstFrameCallback
);
}
}
/// The [Element] that is at the root of the hierarchy (and which wraps the
...
...
@@ -835,9 +832,12 @@ mixin WidgetsBinding on BindingBase, ServicesBinding, SchedulerBinding, GestureB
return
true
;
}());
deferFirstFrameReport
();
if
(
renderViewElement
!=
null
)
buildOwner
.
reassemble
(
renderViewElement
);
return
super
.
performReassemble
();
return
super
.
performReassemble
().
then
((
void
value
)
{
allowFirstFrameReport
();
});
}
}
...
...
packages/flutter/lib/src/widgets/localizations.dart
View file @
4c64b715
...
...
@@ -6,7 +6,6 @@ import 'dart:async';
import
'dart:ui'
show
Locale
;
import
'package:flutter/foundation.dart'
;
import
'package:flutter/rendering.dart'
;
import
'basic.dart'
;
import
'binding.dart'
;
...
...
@@ -520,9 +519,9 @@ class _LocalizationsState extends State<Localizations> {
// have finished loading. Until then the old locale will continue to be used.
// - If we're running at app startup time then defer reporting the first
// "useful" frame until after the async load has completed.
RendererBinding
.
instance
.
deferFirstFrame
();
WidgetsBinding
.
instance
.
deferFirstFrameReport
();
typeToResourcesFuture
.
then
<
void
>((
Map
<
Type
,
dynamic
>
value
)
{
RendererBinding
.
instance
.
allowFirstFrame
();
WidgetsBinding
.
instance
.
allowFirstFrameReport
();
if
(!
mounted
)
return
;
setState
(()
{
...
...
packages/flutter/test/widgets/binding_deferred_first_frame_test.dart
deleted
100644 → 0
View file @
cb35c88b
// Copyright 2019 The Chromium 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:async'
;
import
'package:flutter/rendering.dart'
;
import
'package:flutter_test/flutter_test.dart'
;
import
'package:flutter/material.dart'
;
import
'package:flutter/widgets.dart'
;
const
String
_actualContent
=
'Actual Content'
;
const
String
_loading
=
'Loading...'
;
void
main
(
)
{
testWidgets
(
'deferFirstFrame/allowFirstFrame stops sending frames to engine'
,
(
WidgetTester
tester
)
async
{
expect
(
RendererBinding
.
instance
.
sendFramesToEngine
,
isTrue
);
final
Completer
<
void
>
completer
=
Completer
<
void
>();
await
tester
.
pumpWidget
(
Directionality
(
textDirection:
TextDirection
.
ltr
,
child:
_DeferringWidget
(
key:
UniqueKey
(),
loader:
completer
.
future
,
),
),
);
final
_DeferringWidgetState
state
=
tester
.
state
<
_DeferringWidgetState
>(
find
.
byType
(
_DeferringWidget
));
expect
(
find
.
text
(
_loading
),
findsOneWidget
);
expect
(
find
.
text
(
_actualContent
),
findsNothing
);
expect
(
RendererBinding
.
instance
.
sendFramesToEngine
,
isFalse
);
await
tester
.
pump
();
expect
(
find
.
text
(
_loading
),
findsOneWidget
);
expect
(
find
.
text
(
_actualContent
),
findsNothing
);
expect
(
RendererBinding
.
instance
.
sendFramesToEngine
,
isFalse
);
expect
(
state
.
doneLoading
,
isFalse
);
// Complete the future to start sending frames.
completer
.
complete
();
await
tester
.
idle
();
expect
(
state
.
doneLoading
,
isTrue
);
expect
(
RendererBinding
.
instance
.
sendFramesToEngine
,
isTrue
);
await
tester
.
pump
();
expect
(
find
.
text
(
_loading
),
findsNothing
);
expect
(
find
.
text
(
_actualContent
),
findsOneWidget
);
expect
(
RendererBinding
.
instance
.
sendFramesToEngine
,
isTrue
);
});
}
class
_DeferringWidget
extends
StatefulWidget
{
const
_DeferringWidget
({
Key
key
,
this
.
loader
})
:
super
(
key:
key
);
final
Future
<
void
>
loader
;
@override
State
<
_DeferringWidget
>
createState
()
=>
_DeferringWidgetState
();
}
class
_DeferringWidgetState
extends
State
<
_DeferringWidget
>
{
bool
doneLoading
=
false
;
@override
void
initState
()
{
super
.
initState
();
RendererBinding
.
instance
.
deferFirstFrame
();
widget
.
loader
.
then
((
_
)
{
setState
(()
{
doneLoading
=
true
;
RendererBinding
.
instance
.
allowFirstFrame
();
});
});
}
@override
Widget
build
(
BuildContext
context
)
{
return
doneLoading
?
const
Text
(
_actualContent
)
:
const
Text
(
_loading
);
}
}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment