- 添加输出代码的方式调试 Flutter 应用
- Logging
- Setting breakpoints
- Debug flags: application layers
- Widget tree
- Render tree
- Layer tree
- Semantics tree
- Scheduling
- Debug flags: layout
- Debugging animations
- Debug flags: performance
- Tracing Dart code performance
- Performance overlay
- Widget alignment grid
添加输出代码的方式调试 Flutter 应用
This doc describes debugging features that you can enable in code.For a full list of debugging and profiling tools, see theDebugging page.
Logging
备忘 You can view logs in DevTools’ Logging view or in your system console. This sections shows how to set up your logging statements.
You have two options for logging for your application.The first is to use stdout
and stderr
.Generally, this is done using print()
statements,or by importing dart:io
and invoking methods onstderr
and stdout
. For example:
stderr.writeln('print me');
If you output too much at once, then Android sometimesdiscards some log lines. To avoid this, use debugPrint()
,from Flutter’s foundation
library. This is a wrapper around print
that throttles the output to a level that avoids being dropped byAndroid’s kernel.
The other option for application logging is to use thedart:developer
log()
function. This allows you to include abit more granularity and information in the logging output.Here’s an example:
import 'dart:developer' as developer;
void main() {
developer.log('log me', name: 'my.app.category');
developer.log('log me 1', name: 'my.other.category');
developer.log('log me 2', name: 'my.other.category');
}
You can also pass application data to the log call.The convention for this is to use the error:
namedparameter on the log()
call, JSON encode the objectyou want to send, and pass the encoded string to theerror parameter.
import 'dart:convert';
import 'dart:developer' as developer;
void main() {
var myCustomObject = ...;
developer.log(
'log me',
name: 'my.app.category',
error: jsonEncode(myCustomObject),
);
}
If viewing the logging output in DevTool’s logging view,the JSON encoded error param is interpreted as a data objectand rendered in the details view for that log entry.
Setting breakpoints
备忘 You can set breakpoints in DevTools’ Debugger, or in the built-in debugger of your IDE. If you want to set breakpoints programmatically, use the following instructions.
You can insert programmatic breakpoints using thedebugger()
statement. To use this, you have toimport the dart:developer
package at the top ofthe relevant file.
The debugger()
statement takes an optional when
argument that you can specify to only break when acertain condition is true, as in the following example:
import 'dart:developer';
void someFunction(double offset) {
debugger(when: offset > 30.0);
// ...
}
Debug flags: application layers
Each layer of the Flutter framework provides a function to dump itscurrent state or events to the console (using debugPrint
).
Widget tree
To dump the state of the Widgets library, call debugDumpApp()
.You can call this more or less any time that the application is not inthe middle of running a build phase (in other words, not anywhere inside abuild()
method), so long as the application has built at least once(in other words, any time after calling runApp()
).
For example, the following application:
import 'package:flutter/material.dart';
void main() {
runApp(
MaterialApp(
home: AppHome(),
),
);
}
class AppHome extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Material(
child: Center(
child: FlatButton(
onPressed: () {
debugDumpApp();
},
child: Text('Dump App'),
),
),
);
}
}
The prevous app outputs something like the following(the precise details vary by the version of the framework,the size of the device, and so forth):
I/flutter ( 6559): WidgetsFlutterBinding - CHECKED MODE
I/flutter ( 6559): RenderObjectToWidgetAdapter<RenderBox>([GlobalObjectKey RenderView(497039273)]; renderObject: RenderView)
I/flutter ( 6559): └MaterialApp(state: _MaterialAppState(1009803148))
I/flutter ( 6559): └ScrollConfiguration()
I/flutter ( 6559): └AnimatedTheme(duration: 200ms; state: _AnimatedThemeState(543295893; ticker inactive; ThemeDataTween(ThemeData(Brightness.light Color(0xff2196f3) etc...) → null)))
I/flutter ( 6559): └Theme(ThemeData(Brightness.light Color(0xff2196f3) etc...))
I/flutter ( 6559): └WidgetsApp([GlobalObjectKey _MaterialAppState(1009803148)]; state: _WidgetsAppState(552902158))
I/flutter ( 6559): └CheckedModeBanner()
I/flutter ( 6559): └Banner()
I/flutter ( 6559): └CustomPaint(renderObject: RenderCustomPaint)
I/flutter ( 6559): └DefaultTextStyle(inherit: true; color: Color(0xd0ff0000); family: "monospace"; size: 48.0; weight: 900; decoration: double Color(0xffffff00) TextDecoration.underline)
I/flutter ( 6559): └MediaQuery(MediaQueryData(size: Size(411.4, 683.4), devicePixelRatio: 2.625, textScaleFactor: 1.0, padding: EdgeInsets(0.0, 24.0, 0.0, 0.0)))
I/flutter ( 6559): └LocaleQuery(null)
I/flutter ( 6559): └Title(color: Color(0xff2196f3))
I/flutter ( 6559): └Navigator([GlobalObjectKey<NavigatorState> _WidgetsAppState(552902158)]; state: NavigatorState(240327618; tracking 1 ticker))
I/flutter ( 6559): └Listener(listeners: down, up, cancel; behavior: defer-to-child; renderObject: RenderPointerListener)
I/flutter ( 6559): └AbsorbPointer(renderObject: RenderAbsorbPointer)
I/flutter ( 6559): └Focus([GlobalKey 489139594]; state: _FocusState(739584448))
I/flutter ( 6559): └Semantics(container: true; renderObject: RenderSemanticsAnnotations)
I/flutter ( 6559): └_FocusScope(this scope has focus; focused subscope: [GlobalObjectKey MaterialPageRoute<void>(875520219)])
I/flutter ( 6559): └Overlay([GlobalKey 199833992]; state: OverlayState(619367313; entries: [OverlayEntry@248818791(opaque: false; maintainState: false), OverlayEntry@837336156(opaque: false; maintainState: true)]))
I/flutter ( 6559): └_Theatre(renderObject: _RenderTheatre)
I/flutter ( 6559): └Stack(renderObject: RenderStack)
I/flutter ( 6559): ├_OverlayEntry([GlobalKey 612888877]; state: _OverlayEntryState(739137453))
I/flutter ( 6559): │└IgnorePointer(ignoring: false; renderObject: RenderIgnorePointer)
I/flutter ( 6559): │ └ModalBarrier()
I/flutter ( 6559): │ └Semantics(container: true; renderObject: RenderSemanticsAnnotations)
I/flutter ( 6559): │ └GestureDetector()
I/flutter ( 6559): │ └RawGestureDetector(state: RawGestureDetectorState(39068508; gestures: tap; behavior: opaque))
I/flutter ( 6559): │ └_GestureSemantics(renderObject: RenderSemanticsGestureHandler)
I/flutter ( 6559): │ └Listener(listeners: down; behavior: opaque; renderObject: RenderPointerListener)
I/flutter ( 6559): │ └ConstrainedBox(BoxConstraints(biggest); renderObject: RenderConstrainedBox)
I/flutter ( 6559): └_OverlayEntry([GlobalKey 727622716]; state: _OverlayEntryState(279971240))
I/flutter ( 6559): └_ModalScope([GlobalKey 816151164]; state: _ModalScopeState(875510645))
I/flutter ( 6559): └Focus([GlobalObjectKey MaterialPageRoute<void>(875520219)]; state: _FocusState(331487674))
I/flutter ( 6559): └Semantics(container: true; renderObject: RenderSemanticsAnnotations)
I/flutter ( 6559): └_FocusScope(this scope has focus)
I/flutter ( 6559): └Offstage(offstage: false; renderObject: RenderOffstage)
I/flutter ( 6559): └IgnorePointer(ignoring: false; renderObject: RenderIgnorePointer)
I/flutter ( 6559): └_MountainViewPageTransition(animation: AnimationController(⏭ 1.000; paused; for MaterialPageRoute<void>(/))➩ProxyAnimation➩Cubic(0.40, 0.00, 0.20, 1.00)➩Tween<Offset>(Offset(0.0, 1.0) → Offset(0.0, 0.0))➩Offset(0.0, 0.0); state: _AnimatedState(552160732))
I/flutter ( 6559): └SlideTransition(animation: AnimationController(⏭ 1.000; paused; for MaterialPageRoute<void>(/))➩ProxyAnimation➩Cubic(0.40, 0.00, 0.20, 1.00)➩Tween<Offset>(Offset(0.0, 1.0) → Offset(0.0, 0.0))➩Offset(0.0, 0.0); state: _AnimatedState(714726495))
I/flutter ( 6559): └FractionalTranslation(renderObject: RenderFractionalTranslation)
I/flutter ( 6559): └RepaintBoundary(renderObject: RenderRepaintBoundary)
I/flutter ( 6559): └PageStorage([GlobalKey 619728754])
I/flutter ( 6559): └_ModalScopeStatus(active)
I/flutter ( 6559): └AppHome()
I/flutter ( 6559): └Material(MaterialType.canvas; elevation: 0; state: _MaterialState(780114997))
I/flutter ( 6559): └AnimatedContainer(duration: 200ms; has background; state: _AnimatedContainerState(616063822; ticker inactive; has background))
I/flutter ( 6559): └Container(bg: BoxDecoration())
I/flutter ( 6559): └DecoratedBox(renderObject: RenderDecoratedBox)
I/flutter ( 6559): └Container(bg: BoxDecoration(backgroundColor: Color(0xfffafafa)))
I/flutter ( 6559): └DecoratedBox(renderObject: RenderDecoratedBox)
I/flutter ( 6559): └NotificationListener<LayoutChangedNotification>()
I/flutter ( 6559): └_InkFeature([GlobalKey ink renderer]; renderObject: _RenderInkFeatures)
I/flutter ( 6559): └AnimatedDefaultTextStyle(duration: 200ms; inherit: false; color: Color(0xdd000000); family: "Roboto"; size: 14.0; weight: 400; baseline: alphabetic; state: _AnimatedDefaultTextStyleState(427742350; ticker inactive))
I/flutter ( 6559): └DefaultTextStyle(inherit: false; color: Color(0xdd000000); family: "Roboto"; size: 14.0; weight: 400; baseline: alphabetic)
I/flutter ( 6559): └Center(alignment: Alignment.center; renderObject: RenderPositionedBox)
I/flutter ( 6559): └FlatButton()
I/flutter ( 6559): └MaterialButton(state: _MaterialButtonState(398724090))
I/flutter ( 6559): └ConstrainedBox(BoxConstraints(88.0<=w<=Infinity, h=36.0); renderObject: RenderConstrainedBox relayoutBoundary=up1)
I/flutter ( 6559): └AnimatedDefaultTextStyle(duration: 200ms; inherit: false; color: Color(0xdd000000); family: "Roboto"; size: 14.0; weight: 500; baseline: alphabetic; state: _AnimatedDefaultTextStyleState(315134664; ticker inactive))
I/flutter ( 6559): └DefaultTextStyle(inherit: false; color: Color(0xdd000000); family: "Roboto"; size: 14.0; weight: 500; baseline: alphabetic)
I/flutter ( 6559): └IconTheme(color: Color(0xdd000000))
I/flutter ( 6559): └InkWell(state: _InkResponseState<InkResponse>(369160267))
I/flutter ( 6559): └GestureDetector()
I/flutter ( 6559): └RawGestureDetector(state: RawGestureDetectorState(175370983; gestures: tap; behavior: opaque))
I/flutter ( 6559): └_GestureSemantics(renderObject: RenderSemanticsGestureHandler relayoutBoundary=up2)
I/flutter ( 6559): └Listener(listeners: down; behavior: opaque; renderObject: RenderPointerListener relayoutBoundary=up3)
I/flutter ( 6559): └Container(padding: EdgeInsets(16.0, 0.0, 16.0, 0.0))
I/flutter ( 6559): └Padding(renderObject: RenderPadding relayoutBoundary=up4)
I/flutter ( 6559): └Center(alignment: Alignment.center; widthFactor: 1.0; renderObject: RenderPositionedBox relayoutBoundary=up5)
I/flutter ( 6559): └Text("Dump App")
I/flutter ( 6559): └RichText(renderObject: RenderParagraph relayoutBoundary=up6)
This is the “flattened” tree, showing all the widgets projectedthrough their various build functions. (This is the tree you obtain ifyou call toStringDeep()
on the root of the widget tree.)You’ll see a lot of widgets in there that don’t appear in yourapplication’s source, because they are inserted by the framework’swidgets’ build functions. For example,InkFeature
is an implementation detail of the Material
widget.
Since the debugDumpApp()
call is invoked when the button changesfrom being pressed to being released, it coincides with theFlatButton
object calling setState()
and thus marking itself dirty. That is why, when you look at the dump youshould see that specific object marked as “dirty”. You can also see whatgesture listeners have been registered; in this case, a singleGestureDetector is listed, and it is listening only to a “tap” gesture(“tap” is the output of a TapGestureDetector
’s toStringShort
function).
If you write your own widgets, you can add information by overridingdebugFillProperties()
. Add [DiagnosticsProperty][[]objects to the method’s argument, and call the superclass method.This function is what the toString
method uses to fill in thewidget’s description.
Render tree
If you are trying to debug a layout issue, then the Widgets layer’stree might be insufficiently detailed. In that case, you can dump therendering tree by calling debugDumpRenderTree()
.As with debugDumpApp()
, you can call this more or less any timeexcept during a layout or paint phase. As a general rule,calling it from a frame callbackor an event handler is the best solution.
To call debugDumpRenderTree()
, you need to add import'package:flutter/rendering.dart';
to your source file.
The output for the previous tiny example would look something likethe following:
I/flutter ( 6559): RenderView
I/flutter ( 6559): │ debug mode enabled - android
I/flutter ( 6559): │ window size: Size(1080.0, 1794.0) (in physical pixels)
I/flutter ( 6559): │ device pixel ratio: 2.625 (physical pixels per logical pixel)
I/flutter ( 6559): │ configuration: Size(411.4, 683.4) at 2.625x (in logical pixels)
I/flutter ( 6559): │
I/flutter ( 6559): └─child: RenderCustomPaint
I/flutter ( 6559): │ creator: CustomPaint ← Banner ← CheckedModeBanner ←
I/flutter ( 6559): │ WidgetsApp-[GlobalObjectKey _MaterialAppState(1009803148)] ←
I/flutter ( 6559): │ Theme ← AnimatedTheme ← ScrollConfiguration ← MaterialApp ←
I/flutter ( 6559): │ [root]
I/flutter ( 6559): │ parentData: <none>
I/flutter ( 6559): │ constraints: BoxConstraints(w=411.4, h=683.4)
I/flutter ( 6559): │ size: Size(411.4, 683.4)
I/flutter ( 6559): │
I/flutter ( 6559): └─child: RenderPointerListener
I/flutter ( 6559): │ creator: Listener ← Navigator-[GlobalObjectKey<NavigatorState>
I/flutter ( 6559): │ _WidgetsAppState(552902158)] ← Title ← LocaleQuery ← MediaQuery
I/flutter ( 6559): │ ← DefaultTextStyle ← CustomPaint ← Banner ← CheckedModeBanner ←
I/flutter ( 6559): │ WidgetsApp-[GlobalObjectKey _MaterialAppState(1009803148)] ←
I/flutter ( 6559): │ Theme ← AnimatedTheme ← ⋯
I/flutter ( 6559): │ parentData: <none>
I/flutter ( 6559): │ constraints: BoxConstraints(w=411.4, h=683.4)
I/flutter ( 6559): │ size: Size(411.4, 683.4)
I/flutter ( 6559): │ behavior: defer-to-child
I/flutter ( 6559): │ listeners: down, up, cancel
I/flutter ( 6559): │
I/flutter ( 6559): └─child: RenderAbsorbPointer
I/flutter ( 6559): │ creator: AbsorbPointer ← Listener ←
I/flutter ( 6559): │ Navigator-[GlobalObjectKey<NavigatorState>
I/flutter ( 6559): │ _WidgetsAppState(552902158)] ← Title ← LocaleQuery ← MediaQuery
I/flutter ( 6559): │ ← DefaultTextStyle ← CustomPaint ← Banner ← CheckedModeBanner ←
I/flutter ( 6559): │ WidgetsApp-[GlobalObjectKey _MaterialAppState(1009803148)] ←
I/flutter ( 6559): │ Theme ← ⋯
I/flutter ( 6559): │ parentData: <none>
I/flutter ( 6559): │ constraints: BoxConstraints(w=411.4, h=683.4)
I/flutter ( 6559): │ size: Size(411.4, 683.4)
I/flutter ( 6559): │ absorbing: false
I/flutter ( 6559): │
I/flutter ( 6559): └─child: RenderSemanticsAnnotations
I/flutter ( 6559): │ creator: Semantics ← Focus-[GlobalKey 489139594] ← AbsorbPointer
I/flutter ( 6559): │ ← Listener ← Navigator-[GlobalObjectKey<NavigatorState>
I/flutter ( 6559): │ _WidgetsAppState(552902158)] ← Title ← LocaleQuery ← MediaQuery
I/flutter ( 6559): │ ← DefaultTextStyle ← CustomPaint ← Banner ← CheckedModeBanner ←
I/flutter ( 6559): │ ⋯
I/flutter ( 6559): │ parentData: <none>
I/flutter ( 6559): │ constraints: BoxConstraints(w=411.4, h=683.4)
I/flutter ( 6559): │ size: Size(411.4, 683.4)
I/flutter ( 6559): │
I/flutter ( 6559): └─child: _RenderTheatre
I/flutter ( 6559): │ creator: _Theatre ← Overlay-[GlobalKey 199833992] ← _FocusScope ←
I/flutter ( 6559): │ Semantics ← Focus-[GlobalKey 489139594] ← AbsorbPointer ←
I/flutter ( 6559): │ Listener ← Navigator-[GlobalObjectKey<NavigatorState>
I/flutter ( 6559): │ _WidgetsAppState(552902158)] ← Title ← LocaleQuery ← MediaQuery
I/flutter ( 6559): │ ← DefaultTextStyle ← ⋯
I/flutter ( 6559): │ parentData: <none>
I/flutter ( 6559): │ constraints: BoxConstraints(w=411.4, h=683.4)
I/flutter ( 6559): │ size: Size(411.4, 683.4)
I/flutter ( 6559): │
I/flutter ( 6559): ├─onstage: RenderStack
I/flutter ( 6559): ╎ │ creator: Stack ← _Theatre ← Overlay-[GlobalKey 199833992] ←
I/flutter ( 6559): ╎ │ _FocusScope ← Semantics ← Focus-[GlobalKey 489139594] ←
I/flutter ( 6559): ╎ │ AbsorbPointer ← Listener ←
I/flutter ( 6559): ╎ │ Navigator-[GlobalObjectKey<NavigatorState>
I/flutter ( 6559): ╎ │ _WidgetsAppState(552902158)] ← Title ← LocaleQuery ← MediaQuery
I/flutter ( 6559): ╎ │ ← ⋯
I/flutter ( 6559): ╎ │ parentData: not positioned; offset=Offset(0.0, 0.0)
I/flutter ( 6559): ╎ │ constraints: BoxConstraints(w=411.4, h=683.4)
I/flutter ( 6559): ╎ │ size: Size(411.4, 683.4)
I/flutter ( 6559): ╎ │
I/flutter ( 6559): ╎ ├─child 1: RenderIgnorePointer
I/flutter ( 6559): ╎ │ │ creator: IgnorePointer ← _OverlayEntry-[GlobalKey 612888877] ←
I/flutter ( 6559): ╎ │ │ Stack ← _Theatre ← Overlay-[GlobalKey 199833992] ← _FocusScope
I/flutter ( 6559): ╎ │ │ ← Semantics ← Focus-[GlobalKey 489139594] ← AbsorbPointer ←
I/flutter ( 6559): ╎ │ │ Listener ← Navigator-[GlobalObjectKey<NavigatorState>
I/flutter ( 6559): ╎ │ │ _WidgetsAppState(552902158)] ← Title ← ⋯
I/flutter ( 6559): ╎ │ │ parentData: not positioned; offset=Offset(0.0, 0.0)
I/flutter ( 6559): ╎ │ │ constraints: BoxConstraints(w=411.4, h=683.4)
I/flutter ( 6559): ╎ │ │ size: Size(411.4, 683.4)
I/flutter ( 6559): ╎ │ │ ignoring: false
I/flutter ( 6559): ╎ │ │ ignoringSemantics: implicitly false
I/flutter ( 6559): ╎ │ │
I/flutter ( 6559): ╎ │ └─child: RenderSemanticsAnnotations
I/flutter ( 6559): ╎ │ │ creator: Semantics ← ModalBarrier ← IgnorePointer ←
I/flutter ( 6559): ╎ │ │ _OverlayEntry-[GlobalKey 612888877] ← Stack ← _Theatre ←
I/flutter ( 6559): ╎ │ │ Overlay-[GlobalKey 199833992] ← _FocusScope ← Semantics ←
I/flutter ( 6559): ╎ │ │ Focus-[GlobalKey 489139594] ← AbsorbPointer ← Listener ← ⋯
I/flutter ( 6559): ╎ │ │ parentData: <none>
I/flutter ( 6559): ╎ │ │ constraints: BoxConstraints(w=411.4, h=683.4)
I/flutter ( 6559): ╎ │ │ size: Size(411.4, 683.4)
I/flutter ( 6559): ╎ │ │
I/flutter ( 6559): ╎ │ └─child: RenderSemanticsGestureHandler
I/flutter ( 6559): ╎ │ │ creator: _GestureSemantics ← RawGestureDetector ← GestureDetector
I/flutter ( 6559): ╎ │ │ ← Semantics ← ModalBarrier ← IgnorePointer ←
I/flutter ( 6559): ╎ │ │ _OverlayEntry-[GlobalKey 612888877] ← Stack ← _Theatre ←
I/flutter ( 6559): ╎ │ │ Overlay-[GlobalKey 199833992] ← _FocusScope ← Semantics ← ⋯
I/flutter ( 6559): ╎ │ │ parentData: <none>
I/flutter ( 6559): ╎ │ │ constraints: BoxConstraints(w=411.4, h=683.4)
I/flutter ( 6559): ╎ │ │ size: Size(411.4, 683.4)
I/flutter ( 6559): ╎ │ │
I/flutter ( 6559): ╎ │ └─child: RenderPointerListener
I/flutter ( 6559): ╎ │ │ creator: Listener ← _GestureSemantics ← RawGestureDetector ←
I/flutter ( 6559): ╎ │ │ GestureDetector ← Semantics ← ModalBarrier ← IgnorePointer ←
I/flutter ( 6559): ╎ │ │ _OverlayEntry-[GlobalKey 612888877] ← Stack ← _Theatre ←
I/flutter ( 6559): ╎ │ │ Overlay-[GlobalKey 199833992] ← _FocusScope ← ⋯
I/flutter ( 6559): ╎ │ │ parentData: <none>
I/flutter ( 6559): ╎ │ │ constraints: BoxConstraints(w=411.4, h=683.4)
I/flutter ( 6559): ╎ │ │ size: Size(411.4, 683.4)
I/flutter ( 6559): ╎ │ │ behavior: opaque
I/flutter ( 6559): ╎ │ │ listeners: down
I/flutter ( 6559): ╎ │ │
I/flutter ( 6559): ╎ │ └─child: RenderConstrainedBox
I/flutter ( 6559): ╎ │ creator: ConstrainedBox ← Listener ← _GestureSemantics ←
I/flutter ( 6559): ╎ │ RawGestureDetector ← GestureDetector ← Semantics ← ModalBarrier
I/flutter ( 6559): ╎ │ ← IgnorePointer ← _OverlayEntry-[GlobalKey 612888877] ← Stack ←
I/flutter ( 6559): ╎ │ _Theatre ← Overlay-[GlobalKey 199833992] ← ⋯
I/flutter ( 6559): ╎ │ parentData: <none>
I/flutter ( 6559): ╎ │ constraints: BoxConstraints(w=411.4, h=683.4)
I/flutter ( 6559): ╎ │ size: Size(411.4, 683.4)
I/flutter ( 6559): ╎ │ additionalConstraints: BoxConstraints(biggest)
I/flutter ( 6559): ╎ │
I/flutter ( 6559): ╎ └─child 2: RenderSemanticsAnnotations
I/flutter ( 6559): ╎ │ creator: Semantics ← Focus-[GlobalObjectKey
I/flutter ( 6559): ╎ │ MaterialPageRoute<void>(875520219)] ← _ModalScope-[GlobalKey
I/flutter ( 6559): ╎ │ 816151164] ← _OverlayEntry-[GlobalKey 727622716] ← Stack ←
I/flutter ( 6559): ╎ │ _Theatre ← Overlay-[GlobalKey 199833992] ← _FocusScope ←
I/flutter ( 6559): ╎ │ Semantics ← Focus-[GlobalKey 489139594] ← AbsorbPointer ←
I/flutter ( 6559): ╎ │ Listener ← ⋯
I/flutter ( 6559): ╎ │ parentData: not positioned; offset=Offset(0.0, 0.0)
I/flutter ( 6559): ╎ │ constraints: BoxConstraints(w=411.4, h=683.4)
I/flutter ( 6559): ╎ │ size: Size(411.4, 683.4)
I/flutter ( 6559): ╎ │
I/flutter ( 6559): ╎ └─child: RenderOffstage
I/flutter ( 6559): ╎ │ creator: Offstage ← _FocusScope ← Semantics ←
I/flutter ( 6559): ╎ │ Focus-[GlobalObjectKey MaterialPageRoute<void>(875520219)] ←
I/flutter ( 6559): ╎ │ _ModalScope-[GlobalKey 816151164] ← _OverlayEntry-[GlobalKey
I/flutter ( 6559): ╎ │ 727622716] ← Stack ← _Theatre ← Overlay-[GlobalKey 199833992] ←
I/flutter ( 6559): ╎ │ _FocusScope ← Semantics ← Focus-[GlobalKey 489139594] ← ⋯
I/flutter ( 6559): ╎ │ parentData: <none>
I/flutter ( 6559): ╎ │ constraints: BoxConstraints(w=411.4, h=683.4)
I/flutter ( 6559): ╎ │ size: Size(411.4, 683.4)
I/flutter ( 6559): ╎ │ offstage: false
I/flutter ( 6559): ╎ │
I/flutter ( 6559): ╎ └─child: RenderIgnorePointer
I/flutter ( 6559): ╎ │ creator: IgnorePointer ← Offstage ← _FocusScope ← Semantics ←
I/flutter ( 6559): ╎ │ Focus-[GlobalObjectKey MaterialPageRoute<void>(875520219)] ←
I/flutter ( 6559): ╎ │ _ModalScope-[GlobalKey 816151164] ← _OverlayEntry-[GlobalKey
I/flutter ( 6559): ╎ │ 727622716] ← Stack ← _Theatre ← Overlay-[GlobalKey 199833992] ←
I/flutter ( 6559): ╎ │ _FocusScope ← Semantics ← ⋯
I/flutter ( 6559): ╎ │ parentData: <none>
I/flutter ( 6559): ╎ │ constraints: BoxConstraints(w=411.4, h=683.4)
I/flutter ( 6559): ╎ │ size: Size(411.4, 683.4)
I/flutter ( 6559): ╎ │ ignoring: false
I/flutter ( 6559): ╎ │ ignoringSemantics: implicitly false
I/flutter ( 6559): ╎ │
I/flutter ( 6559): ╎ └─child: RenderFractionalTranslation
I/flutter ( 6559): ╎ │ creator: FractionalTranslation ← SlideTransition ←
I/flutter ( 6559): ╎ │ _MountainViewPageTransition ← IgnorePointer ← Offstage ←
I/flutter ( 6559): ╎ │ _FocusScope ← Semantics ← Focus-[GlobalObjectKey
I/flutter ( 6559): ╎ │ MaterialPageRoute<void>(875520219)] ← _ModalScope-[GlobalKey
I/flutter ( 6559): ╎ │ 816151164] ← _OverlayEntry-[GlobalKey 727622716] ← Stack ←
I/flutter ( 6559): ╎ │ _Theatre ← ⋯
I/flutter ( 6559): ╎ │ parentData: <none>
I/flutter ( 6559): ╎ │ constraints: BoxConstraints(w=411.4, h=683.4)
I/flutter ( 6559): ╎ │ size: Size(411.4, 683.4)
I/flutter ( 6559): ╎ │ translation: Offset(0.0, 0.0)
I/flutter ( 6559): ╎ │ transformHitTests: true
I/flutter ( 6559): ╎ │
I/flutter ( 6559): ╎ └─child: RenderRepaintBoundary
I/flutter ( 6559): ╎ │ creator: RepaintBoundary ← FractionalTranslation ←
I/flutter ( 6559): ╎ │ SlideTransition ← _MountainViewPageTransition ← IgnorePointer ←
I/flutter ( 6559): ╎ │ Offstage ← _FocusScope ← Semantics ← Focus-[GlobalObjectKey
I/flutter ( 6559): ╎ │ MaterialPageRoute<void>(875520219)] ← _ModalScope-[GlobalKey
I/flutter ( 6559): ╎ │ 816151164] ← _OverlayEntry-[GlobalKey 727622716] ← Stack ← ⋯
I/flutter ( 6559): ╎ │ parentData: <none>
I/flutter ( 6559): ╎ │ constraints: BoxConstraints(w=411.4, h=683.4)
I/flutter ( 6559): ╎ │ size: Size(411.4, 683.4)
I/flutter ( 6559): ╎ │ metrics: 83.3% useful (1 bad vs 5 good)
I/flutter ( 6559): ╎ │ diagnosis: this is a useful repaint boundary and should be kept
I/flutter ( 6559): ╎ │
I/flutter ( 6559): ╎ └─child: RenderDecoratedBox
I/flutter ( 6559): ╎ │ creator: DecoratedBox ← Container ← AnimatedContainer ← Material
I/flutter ( 6559): ╎ │ ← AppHome ← _ModalScopeStatus ← PageStorage-[GlobalKey
I/flutter ( 6559): ╎ │ 619728754] ← RepaintBoundary ← FractionalTranslation ←
I/flutter ( 6559): ╎ │ SlideTransition ← _MountainViewPageTransition ← IgnorePointer ←
I/flutter ( 6559): ╎ │ ⋯
I/flutter ( 6559): ╎ │ parentData: <none>
I/flutter ( 6559): ╎ │ constraints: BoxConstraints(w=411.4, h=683.4)
I/flutter ( 6559): ╎ │ size: Size(411.4, 683.4)
I/flutter ( 6559): ╎ │ decoration:
I/flutter ( 6559): ╎ │ <no decorations specified>
I/flutter ( 6559): ╎ │ configuration: ImageConfiguration(bundle:
I/flutter ( 6559): ╎ │ PlatformAssetBundle@367106502(), devicePixelRatio: 2.625,
I/flutter ( 6559): ╎ │ platform: android)
I/flutter ( 6559): ╎ │
I/flutter ( 6559): ╎ └─child: RenderDecoratedBox
I/flutter ( 6559): ╎ │ creator: DecoratedBox ← Container ← DecoratedBox ← Container ←
I/flutter ( 6559): ╎ │ AnimatedContainer ← Material ← AppHome ← _ModalScopeStatus ←
I/flutter ( 6559): ╎ │ PageStorage-[GlobalKey 619728754] ← RepaintBoundary ←
I/flutter ( 6559): ╎ │ FractionalTranslation ← SlideTransition ← ⋯
I/flutter ( 6559): ╎ │ parentData: <none>
I/flutter ( 6559): ╎ │ constraints: BoxConstraints(w=411.4, h=683.4)
I/flutter ( 6559): ╎ │ size: Size(411.4, 683.4)
I/flutter ( 6559): ╎ │ decoration:
I/flutter ( 6559): ╎ │ backgroundColor: Color(0xfffafafa)
I/flutter ( 6559): ╎ │ configuration: ImageConfiguration(bundle:
I/flutter ( 6559): ╎ │ PlatformAssetBundle@367106502(), devicePixelRatio: 2.625,
I/flutter ( 6559): ╎ │ platform: android)
I/flutter ( 6559): ╎ │
I/flutter ( 6559): ╎ └─child: _RenderInkFeatures
I/flutter ( 6559): ╎ │ creator: _InkFeature-[GlobalKey ink renderer] ←
I/flutter ( 6559): ╎ │ NotificationListener<LayoutChangedNotification> ← DecoratedBox
I/flutter ( 6559): ╎ │ ← Container ← DecoratedBox ← Container ← AnimatedContainer ←
I/flutter ( 6559): ╎ │ Material ← AppHome ← _ModalScopeStatus ← PageStorage-[GlobalKey
I/flutter ( 6559): ╎ │ 619728754] ← RepaintBoundary ← ⋯
I/flutter ( 6559): ╎ │ parentData: <none>
I/flutter ( 6559): ╎ │ constraints: BoxConstraints(w=411.4, h=683.4)
I/flutter ( 6559): ╎ │ size: Size(411.4, 683.4)
I/flutter ( 6559): ╎ │
I/flutter ( 6559): ╎ └─child: RenderPositionedBox
I/flutter ( 6559): ╎ │ creator: Center ← DefaultTextStyle ← AnimatedDefaultTextStyle ←
I/flutter ( 6559): ╎ │ _InkFeature-[GlobalKey ink renderer] ←
I/flutter ( 6559): ╎ │ NotificationListener<LayoutChangedNotification> ← DecoratedBox
I/flutter ( 6559): ╎ │ ← Container ← DecoratedBox ← Container ← AnimatedContainer ←
I/flutter ( 6559): ╎ │ Material ← AppHome ← ⋯
I/flutter ( 6559): ╎ │ parentData: <none>
I/flutter ( 6559): ╎ │ constraints: BoxConstraints(w=411.4, h=683.4)
I/flutter ( 6559): ╎ │ size: Size(411.4, 683.4)
I/flutter ( 6559): ╎ │ alignment: Alignment.center
I/flutter ( 6559): ╎ │ widthFactor: expand
I/flutter ( 6559): ╎ │ heightFactor: expand
I/flutter ( 6559): ╎ │
I/flutter ( 6559): ╎ └─child: RenderConstrainedBox relayoutBoundary=up1
I/flutter ( 6559): ╎ │ creator: ConstrainedBox ← MaterialButton ← FlatButton ← Center ←
I/flutter ( 6559): ╎ │ DefaultTextStyle ← AnimatedDefaultTextStyle ←
I/flutter ( 6559): ╎ │ _InkFeature-[GlobalKey ink renderer] ←
I/flutter ( 6559): ╎ │ NotificationListener<LayoutChangedNotification> ← DecoratedBox
I/flutter ( 6559): ╎ │ ← Container ← DecoratedBox ← Container ← ⋯
I/flutter ( 6559): ╎ │ parentData: offset=Offset(156.7, 323.7)
I/flutter ( 6559): ╎ │ constraints: BoxConstraints(0.0<=w<=411.4, 0.0<=h<=683.4)
I/flutter ( 6559): ╎ │ size: Size(98.0, 36.0)
I/flutter ( 6559): ╎ │ additionalConstraints: BoxConstraints(88.0<=w<=Infinity, h=36.0)
I/flutter ( 6559): ╎ │
I/flutter ( 6559): ╎ └─child: RenderSemanticsGestureHandler relayoutBoundary=up2
I/flutter ( 6559): ╎ │ creator: _GestureSemantics ← RawGestureDetector ← GestureDetector
I/flutter ( 6559): ╎ │ ← InkWell ← IconTheme ← DefaultTextStyle ←
I/flutter ( 6559): ╎ │ AnimatedDefaultTextStyle ← ConstrainedBox ← MaterialButton ←
I/flutter ( 6559): ╎ │ FlatButton ← Center ← DefaultTextStyle ← ⋯
I/flutter ( 6559): ╎ │ parentData: <none>
I/flutter ( 6559): ╎ │ constraints: BoxConstraints(88.0<=w<=411.4, h=36.0)
I/flutter ( 6559): ╎ │ size: Size(98.0, 36.0)
I/flutter ( 6559): ╎ │
I/flutter ( 6559): ╎ └─child: RenderPointerListener relayoutBoundary=up3
I/flutter ( 6559): ╎ │ creator: Listener ← _GestureSemantics ← RawGestureDetector ←
I/flutter ( 6559): ╎ │ GestureDetector ← InkWell ← IconTheme ← DefaultTextStyle ←
I/flutter ( 6559): ╎ │ AnimatedDefaultTextStyle ← ConstrainedBox ← MaterialButton ←
I/flutter ( 6559): ╎ │ FlatButton ← Center ← ⋯
I/flutter ( 6559): ╎ │ parentData: <none>
I/flutter ( 6559): ╎ │ constraints: BoxConstraints(88.0<=w<=411.4, h=36.0)
I/flutter ( 6559): ╎ │ size: Size(98.0, 36.0)
I/flutter ( 6559): ╎ │ behavior: opaque
I/flutter ( 6559): ╎ │ listeners: down
I/flutter ( 6559): ╎ │
I/flutter ( 6559): ╎ └─child: RenderPadding relayoutBoundary=up4
I/flutter ( 6559): ╎ │ creator: Padding ← Container ← Listener ← _GestureSemantics ←
I/flutter ( 6559): ╎ │ RawGestureDetector ← GestureDetector ← InkWell ← IconTheme ←
I/flutter ( 6559): ╎ │ DefaultTextStyle ← AnimatedDefaultTextStyle ← ConstrainedBox ←
I/flutter ( 6559): ╎ │ MaterialButton ← ⋯
I/flutter ( 6559): ╎ │ parentData: <none>
I/flutter ( 6559): ╎ │ constraints: BoxConstraints(88.0<=w<=411.4, h=36.0)
I/flutter ( 6559): ╎ │ size: Size(98.0, 36.0)
I/flutter ( 6559): ╎ │ padding: EdgeInsets(16.0, 0.0, 16.0, 0.0)
I/flutter ( 6559): ╎ │
I/flutter ( 6559): ╎ └─child: RenderPositionedBox relayoutBoundary=up5
I/flutter ( 6559): ╎ │ creator: Center ← Padding ← Container ← Listener ←
I/flutter ( 6559): ╎ │ _GestureSemantics ← RawGestureDetector ← GestureDetector ←
I/flutter ( 6559): ╎ │ InkWell ← IconTheme ← DefaultTextStyle ←
I/flutter ( 6559): ╎ │ AnimatedDefaultTextStyle ← ConstrainedBox ← ⋯
I/flutter ( 6559): ╎ │ parentData: offset=Offset(16.0, 0.0)
I/flutter ( 6559): ╎ │ constraints: BoxConstraints(56.0<=w<=379.4, h=36.0)
I/flutter ( 6559): ╎ │ size: Size(66.0, 36.0)
I/flutter ( 6559): ╎ │ alignment: Alignment.center
I/flutter ( 6559): ╎ │ widthFactor: 1.0
I/flutter ( 6559): ╎ │ heightFactor: expand
I/flutter ( 6559): ╎ │
I/flutter ( 6559): ╎ └─child: RenderParagraph relayoutBoundary=up6
I/flutter ( 6559): ╎ │ creator: RichText ← Text ← Center ← Padding ← Container ←
I/flutter ( 6559): ╎ │ Listener ← _GestureSemantics ← RawGestureDetector ←
I/flutter ( 6559): ╎ │ GestureDetector ← InkWell ← IconTheme ← DefaultTextStyle ← ⋯
I/flutter ( 6559): ╎ │ parentData: offset=Offset(0.0, 10.0)
I/flutter ( 6559): ╎ │ constraints: BoxConstraints(0.0<=w<=379.4, 0.0<=h<=36.0)
I/flutter ( 6559): ╎ │ size: Size(66.0, 16.0)
I/flutter ( 6559): ╎ ╘═╦══ text ═══
I/flutter ( 6559): ╎ ║ TextSpan:
I/flutter ( 6559): ╎ ║ inherit: false
I/flutter ( 6559): ╎ ║ color: Color(0xdd000000)
I/flutter ( 6559): ╎ ║ family: "Roboto"
I/flutter ( 6559): ╎ ║ size: 14.0
I/flutter ( 6559): ╎ ║ weight: 500
I/flutter ( 6559): ╎ ║ baseline: alphabetic
I/flutter ( 6559): ╎ ║ "Dump App"
I/flutter ( 6559): ╎ ╚═══════════
I/flutter ( 6559): ╎
I/flutter ( 6559): └╌no offstage children
This is the output of the root RenderObject
object’stoStringDeep()
function.
When debugging layout issues, the key fields to look at are thesize
and constraints
fields. The constraints flow down the tree,and the sizes flow back up.
For example, in the previous dump you can see that the window size,Size(411.4, 683.4)
, is used to force all the boxes down to theRenderPositionedBox
to be the size of the screen, withconstraints of BoxConstraints(w=411.4, h=683.4)
.The RenderPositionedBox
, which the dump says was created by aCenter
widget (as described by the creator
field),sets its child’s constraints to a loose version of this:BoxConstraints(0.0<=w<=411.4, 0.0<=h<=683.4)
. The child, aRenderPadding
, further inserts these constraints to ensurethere is room for the padding, and thus the [
RenderConstrainedBox][]has a loose constraint of
BoxConstraints(0.0<=w<=395.4,0.0<=h<=667.4). This object, which the
creator field tells us isprobably part of the [
FlatButton][]'s definition,sets a minimum width of 88 pixels on its contents and aspecific height of 36.0. (This is the
FlatButton` class implementingthe Material Design guidelines regarding button dimensions.)
The inner-most RenderPositionedBox
loosens the constraints again,this time to center the text within the button. TheRenderParagraph
picks its size based on its contents.If you now follow the sizes back up the chain,you’ll see how the text’s size is what influences thewidth of all the boxes that form the button, as they all take theirchild’s dimensions to size themselves.
Another way to notice this is by looking at the “relayoutSubtreeRoot”part of the descriptions of each box, which essentially tells you howmany ancestors depend on this element’s size in some way.Thus the RenderParagraph
has a relayoutSubtreeRoot=up8
,meaning that when the RenderParagraph
is dirtied,eight ancestors also have to be dirtied because they might beaffected by the new dimensions.
If you write your own render objects, you can add information to thedump by overriding debugFillProperties()
.Add DiagnosticsPropertyobjects to the method’s argument, and call the superclass method.
Layer tree
If you are trying to debug a compositing issue, you can usedebugDumpLayerTree()
.For the previous example, it would output:
I/flutter : TransformLayer
I/flutter : │ creator: [root]
I/flutter : │ offset: Offset(0.0, 0.0)
I/flutter : │ transform:
I/flutter : │ [0] 3.5,0.0,0.0,0.0
I/flutter : │ [1] 0.0,3.5,0.0,0.0
I/flutter : │ [2] 0.0,0.0,1.0,0.0
I/flutter : │ [3] 0.0,0.0,0.0,1.0
I/flutter : │
I/flutter : ├─child 1: OffsetLayer
I/flutter : │ │ creator: RepaintBoundary ← _FocusScope ← Semantics ← Focus-[GlobalObjectKey MaterialPageRoute(560156430)] ← _ModalScope-[GlobalKey 328026813] ← _OverlayEntry-[GlobalKey 388965355] ← Stack ← Overlay-[GlobalKey 625702218] ← Navigator-[GlobalObjectKey _MaterialAppState(859106034)] ← Title ← ⋯
I/flutter : │ │ offset: Offset(0.0, 0.0)
I/flutter : │ │
I/flutter : │ └─child 1: PictureLayer
I/flutter : │
I/flutter : └─child 2: PictureLayer
This is the output of calling toStringDeep
on the root Layer
object.
The transform at the root is the transform that applies the devicepixel ratio; in this case, a ratio of 3.5 device pixels for everylogical pixel.
The RepaintBoundary
widget, which creates a RenderRepaintBoundary
in the render tree, creates a new layer in the layer tree. This isused to reduce how much needs to be repainted.
Semantics tree
You can also obtain a dump of the Semantics tree(the tree presented to the system accessibility APIs) usingdebugDumpSemanticsTree()
. To use this,you have to have first enable accessibility, for example, byenabling a system accessibility tool or the SemanticsDebugger
.
For the previous example, it would output the following:
I/flutter : SemanticsNode(0; Rect.fromLTRB(0.0, 0.0, 411.4, 683.4))
I/flutter : ├SemanticsNode(1; Rect.fromLTRB(0.0, 0.0, 411.4, 683.4))
I/flutter : │ └SemanticsNode(2; Rect.fromLTRB(0.0, 0.0, 411.4, 683.4); canBeTapped)
I/flutter : └SemanticsNode(3; Rect.fromLTRB(0.0, 0.0, 411.4, 683.4))
I/flutter : └SemanticsNode(4; Rect.fromLTRB(0.0, 0.0, 82.0, 36.0); canBeTapped; "Dump App")
Scheduling
To find out where your events happen relative to the frame’sbegin/end, you can toggle the debugPrintBeginFrameBanner
and the debugPrintEndFrameBanner
booleans to print thebeginning and end of the frames to the console.
For example:
I/flutter : ▄▄▄▄▄▄▄▄ Frame 12 30s 437.086ms ▄▄▄▄▄▄▄▄
I/flutter : Debug print: Am I performing this work more than once per frame?
I/flutter : Debug print: Am I performing this work more than once per frame?
I/flutter : ▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀
The debugPrintScheduleFrameStacks
flag can also be usedto print the call stack causing the current frame to be scheduled.
Debug flags: layout
You can also debug a layout problem visually, by settingdebugPaintSizeEnabled
to true
.This is a boolean from the rendering
library. It can beenabled at any time and affects all painting while it is true.The easiest way to set it is at the top of your void main()
entry point. See an example in the following code:
//add import to rendering library
import 'package:flutter/rendering.dart';
void main() {
debugPaintSizeEnabled=true;
runApp(MyApp());
}
When it is enabled, all boxes get a bright teal border,padding (from widgets like Padding
) is shown in fadedblue with a darker blue box around the child, alignment(from widgets like Center
and Align
) is shown withyellow arrows, and spacers (from widgets likeContainer
when they have no child) are shown in gray.
The debugPaintBaselinesEnabled
flagdoes something similar but for objects with baselines.The alphabetic baseline is shown in bright green and theideographic baseline in orange.
The debugPaintPointersEnabled
flag turns on aspecial mode whereby any objects that are being tappedget highlighted in teal. This can help you determinewhether an object is somehow failing to correctly hittest (which might happen if, for instance, it is actuallyoutside the bounds of its parent and thus notbeing considered for hit testing in the first place).
If you’re trying to debug compositor layers, for exampleto determine whether and where to add RepaintBoundary
widgets, you can use the debugPaintLayerBordersEnabled
flag, which outlines each layer’s bounds in orange,or the debugRepaintRainbowEnabled
flag,which causes layers to be overlayed with a rotating set ofcolors whenever they are repainted.
All of these flags only work in debug mode.In general, anything in the Flutter framework that starts with“debug…
” only works in debug mode.
Debugging animations
备忘 The easiest way to debug animations is to slow them down. You can do this using the Slow Animations button in DevTools’ Inspector view, which slows down the animation by 5x. If you want more control over the amount of slowness, use the following instructions.
Set the timeDilation
variable (from the scheduler
library) to a number greater than 1.0, for instance, 50.0.It’s best to only set this once on app startup. If youchange it on the fly, especially if you reduce it whileanimations are running, it’s possible that the frameworkwill observe time going backwards, which will probablyresult in asserts and generally interfere with your efforts.
Debug flags: performance
备忘 You can achieve similar results to some of these debug flags using DevTools. Some of the debug flags aren’t particularly useful. If you find a flag that has functionality you would like to see added to DevTools, please file an issue.
Flutter provides a wide variety of debug flags and functionsto help you debug your app at various points along thedevelopment cycle. To use these features, you must compilein debug mode. The following list, while not complete,highlights some of flags (and one function) from therendering library for debugging performance issues.
You can set these flags either by editing the framework code,or by importing the module and setting the value in yourmain()
method, following by a hot restart.
debugDumpRenderTree()
Call this function when not in a layout or repaint phase to dump the rendering tree to the console. (Pressing t from
flutter run
calls this command.) Search for “RepaintBoundary” to see diagnostics on how useful a boundary is.debugPaintLayerBordersEnabled
PENDING
debugRepaintRainbowEnabled
You can enable this flag in the Flutter inspector by selecting the Repaint Rainbow button. If any static widgets are rotating through the colors of the rainbow (for example, a static header), those areas are candidates for adding repaint boundaries.
debugPrintMarkNeedsLayoutStacks
Enable this flag if you’re seeing more layouts than you expect (for example, on the timeline, on a profile, or from a
print
statement inside a layout method). Once enabled, the console is flooded with stack traces showing why each render object is being marked dirty for layout. You can use thedebugPrintStack()
method from theservices
library to print your own stack traces on demand, if this kind of approach is useful to you.debugPrintMarkNeedsPaintStacks
- Similar to
debugPrintMarkNeedsLayoutStacks
, but for excess painting. You can use thedebugPrintStack()
method from theservices
library to print your own stack traces on demand, if this kind of approach is useful to you.
Tracing Dart code performance
备忘 You can use the DevTools Timeline view to perform traces. You can also import and export trace files into the Timeline view, but only files generated by DevTools.
To perform custom performance traces programmatically andmeasure wall/CPU time of arbitrary segments of Dart codesimilar to what would be done on Android with systrace,use dart:developer
Timeline utilities to wrap thecode you want to measure such as:
import 'dart:developer';
Timeline.startSync('interesting function');
// iWonderHowLongThisTakes();
Timeline.finishSync();
Then open your app’s Observatory’s timeline page, check the ‘Dart’recording option and perform the function you want to measure.
Refreshing the page displays the chronological timeline recordsof your app in Chrome’s tracing tool.
Be sure to run your app in profile mode to ensure that theruntime performance characteristics closely match that of yourfinal product.
Performance overlay
备忘 You can toggle display of the performance overlay on your app using the Performance Overlay button in the Flutter inspector. If you prefer to do it in code, use the following instructions.
You can programmatically enable the PerformanceOverlay widget bysetting the showPerformanceOverlay
property to true
on theMaterialApp
, CupertinoApp
, or WidgetsApp
constructor:
- class MyApp extends StatelessWidget {
- @override
- Widget build(BuildContext context) {
- return MaterialApp(
- showPerformanceOverlay: true,
- title: 'My Awesome App',
- theme: ThemeData(
- primarySwatch: Colors.blue,
- ),
- home: MyHomePage(title: 'My Awesome App'),
- );
- }
- }
(If you’re not using MaterialApp
, CupertinoApp
,or WidgetsApp
, you can get the same effect by wrapping yourapplication in a stack and putting a widget on your stack that wascreated by calling PerformanceOverlay.allEnabled()
.)
For information on how to interpret the graphs in the overlay,see The performance overlay inProfiling Flutter performance.
Widget alignment grid
You can programmatically overlay aMaterial Design baseline grid on top of your app tohelp verify alignments by using thedebugShowMaterialGrid
argument in theMaterialApp
constructor.
In non-Material applications, you can achieve a similareffect by using a GridPaper
widget directly.