Flutter 調(diào)試應(yīng)用

2020-08-27 14:48 更新

Dart 分析器

在運(yùn)行應(yīng)用程序前,請(qǐng)運(yùn)行flutter analyze測(cè)試你的代碼。這個(gè)工具(它是dartanalyzer工具的一個(gè)包裝)將分析你的代碼并幫助你發(fā)現(xiàn)可能的錯(cuò)誤。 如果你使用IntelliJ的Flutter插件,那么已經(jīng)自動(dòng)啟用了。

Dart分析器大量使用了代碼中的類(lèi)型注釋來(lái)幫助追蹤問(wèn)題。我們鼓勵(lì)您在任何地方使用它們(避免var、無(wú)類(lèi)型的參數(shù)、無(wú)類(lèi)型的列表文字等),因?yàn)檫@是追蹤問(wèn)題的最快的方式。

Dart Observatory (語(yǔ)句級(jí)的單步調(diào)試和分析器)

如果您使用flutter run啟動(dòng)應(yīng)用程序,那么當(dāng)它運(yùn)行時(shí),您可以打開(kāi)Observatory URL的Web頁(yè)面(例如Observatory監(jiān)聽(tīng)http://127.0.0.1:8100/), 直接使用語(yǔ)句級(jí)單步調(diào)試器連接到您的應(yīng)用程序。如果您使用的是IntelliJ,則還可以使用其內(nèi)置的調(diào)試器來(lái)調(diào)試您的應(yīng)用程序。

Observatory 同時(shí)支持分析、檢查堆等。有關(guān)Observatory的更多信息請(qǐng)參考Observatory 文檔.

如果您使用Observatory進(jìn)行分析,請(qǐng)確保通過(guò)--profile選項(xiàng)來(lái)運(yùn)行flutter run命令來(lái)運(yùn)行應(yīng)用程序。 否則,配置文件中將出現(xiàn)的主要問(wèn)題將是調(diào)試斷言,以驗(yàn)證框架的各種不變量(請(qǐng)參閱下面的“調(diào)試模式斷言”)。

debugger() 聲明

當(dāng)使用Dart Observatory(或另一個(gè)Dart調(diào)試器,例如IntelliJ IDE中的調(diào)試器)時(shí),可以使用該debugger()語(yǔ)句插入編程式斷點(diǎn)。要使用這個(gè),你必須添加import 'dart:developer';到相關(guān)文件頂部。

debugger()語(yǔ)句采用一個(gè)可選when參數(shù),您可以指定該參數(shù)僅在特定條件為真時(shí)中斷,如下所示:

void someFunction(double offset) {
  debugger(when: offset > 30.0);
  // ...
}

print、debugPrint、flutter logs

Dart print()功能將輸出到系統(tǒng)控制臺(tái),您可以使用flutter logs了查看它(基本上是一個(gè)包裝adb logcat)。

如果你一次輸出太多,那么Android有時(shí)會(huì)丟棄一些日志行。為了避免這種情況,您可以使用Flutter的foundation庫(kù)中的debugPrint()。 這是一個(gè)封裝print,它將輸出限制在一個(gè)級(jí)別,避免被Android內(nèi)核丟棄。

Flutter框架中的許多類(lèi)都有toString實(shí)現(xiàn)。按照慣例,這些輸出通常包括對(duì)象的runtimeType單行輸出,通常在表單中ClassName(more information about this instance…)。 樹(shù)中使用的一些類(lèi)也具有toStringDeep,從該點(diǎn)返回整個(gè)子樹(shù)的多行描述。已一些具有詳細(xì)信息toString的類(lèi)會(huì)實(shí)現(xiàn)一個(gè)toStringShort,它只返回對(duì)象的類(lèi)型或其他非常簡(jiǎn)短的(一個(gè)或兩個(gè)單詞)描述。

調(diào)試模式斷言

在開(kāi)發(fā)過(guò)程中,強(qiáng)烈建議您使用Flutter的“調(diào)試”模式,有時(shí)也稱(chēng)為“checked”模式(譯者語(yǔ):Dart2.0后“checked”被廢除,可以使用“strong” mode)。 如果您使用flutter run運(yùn)行程序。在這種模式下,Dart assert語(yǔ)句被啟用,并且Flutter框架使用它來(lái)執(zhí)行許多運(yùn)行時(shí)檢查來(lái)驗(yàn)證是否違反一些不可變的規(guī)則。

當(dāng)一個(gè)不可變的規(guī)則被違反時(shí),它被報(bào)告給控制臺(tái),并帶有一些上下文信息來(lái)幫助追蹤問(wèn)題的根源。

要關(guān)閉調(diào)試模式并使用發(fā)布模式,請(qǐng)使用flutter run --release運(yùn)行您的應(yīng)用程序。 這也關(guān)閉了Observatory調(diào)試器。一個(gè)中間模式可以關(guān)閉除Observatory之外所有調(diào)試輔助工具的,稱(chēng)為“profile mode”,用--profile替代--release即可。

調(diào)試應(yīng)用程序?qū)?/h2>

Flutter框架的每一層都提供了將其當(dāng)前狀態(tài)或事件轉(zhuǎn)儲(chǔ)(dump)到控制臺(tái)(使用debugPrint)的功能。

Widget 層

要轉(zhuǎn)儲(chǔ)Widgets庫(kù)的狀態(tài),請(qǐng)調(diào)用debugDumpApp()。 只要應(yīng)用程序已經(jīng)構(gòu)建了至少一次(即在調(diào)用build()之后的任何時(shí)間),您可以在應(yīng)用程序未處于構(gòu)建階段(即,不在build()方法內(nèi)調(diào)用 )的任何時(shí)間調(diào)用此方法(在調(diào)用runApp()之后)。

如, 這個(gè)應(yīng)用程序:

import 'package:flutter/material.dart';

void main() {
  runApp(
    new MaterialApp(
      home: new AppHome(),
    ),
  );
}

class AppHome extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return new Material(
      child: new Center(
        child: new FlatButton(
          onPressed: () {
            debugDumpApp();
          },
          child: new Text('Dump App'),
        ),
      ),
    );
  }
}

…會(huì)輸出這樣的內(nèi)容(精確的細(xì)節(jié)會(huì)根據(jù)框架的版本、設(shè)備的大小等等而變化):

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<Null>(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<Null>(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<Null>(/))?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<Null>(/))?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)

這是一個(gè)“扁平化”的樹(shù),顯示了通過(guò)各種構(gòu)建函數(shù)投影的所有widget(如果你在widget樹(shù)的根中調(diào)用toStringDeepwidget,這是你獲得的樹(shù))。 你會(huì)看到很多在你的應(yīng)用源代碼中沒(méi)有出現(xiàn)的widget,因?yàn)樗鼈儽豢蚣艿膚idget的build()函數(shù)插入的。例如,InkFeature是Material widget的一個(gè)實(shí)現(xiàn)細(xì)節(jié) 。

由于debugDumpApp()當(dāng)按鈕從被按下變?yōu)楸会尫艜r(shí)被調(diào)用,F(xiàn)latButton對(duì)象同時(shí)調(diào)用setState(),所以并因此將自己標(biāo)記為臟。 這就是為什么如果你看轉(zhuǎn)儲(chǔ),你會(huì)看到特定的對(duì)象標(biāo)記為“dirty”。您還可以查看已注冊(cè)了哪些手勢(shì)監(jiān)聽(tīng)器; 在這種情況下,一個(gè)單一的GestureDetector被列出,并且監(jiān)聽(tīng)“tap”手勢(shì)(“tap”是TapGestureDetector的toStringShort函數(shù)輸出的)

如果您編寫(xiě)自己的widget,則可以通過(guò)覆蓋debugFillProperties()來(lái)添加信息。 將DiagnosticsProperty對(duì)象作為方法參數(shù),并調(diào)用父類(lèi)方法。 該函數(shù)是該toString方法用來(lái)填充小部件描述信息的。

渲染層

如果您嘗試調(diào)試布局問(wèn)題,那么Widgets層的樹(shù)可能不夠詳細(xì)。在這種情況下,您可以通過(guò)調(diào)用debugDumpRenderTree()轉(zhuǎn)儲(chǔ)渲染樹(shù)。 正如debugDumpApp(),除布局或繪制階段外,您可以隨時(shí)調(diào)用此函數(shù)。作為一般規(guī)則,從frame 回調(diào) 或事件處理器中調(diào)用它是最佳解決方案。

要調(diào)用debugDumpRenderTree(),您需要添加import'package:flutter/rendering.dart';到您的源文件。

上面這個(gè)小例子的輸出結(jié)果如下所示:

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<Null>(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<Null>(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<Null>(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<Null>(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<Null>(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

這是根RenderObject對(duì)象的toStringDeep函數(shù)的輸出。

當(dāng)調(diào)試布局問(wèn)題時(shí),關(guān)鍵要看的是size和constraints字段。約束沿著樹(shù)向下傳遞,尺寸向上傳遞。

例如,在上面的轉(zhuǎn)儲(chǔ)中,您可以看到窗口大小,Size(411.4, 683.4),它用于強(qiáng)制RenderPositionedBox下的所有渲染框到屏幕的大小, 約束條件為 BoxConstraints(w=411.4, h=683.4)。從RenderPositionedBox的轉(zhuǎn)儲(chǔ)中看到是由Center widget創(chuàng)建的(如creator字段所描述的), 設(shè)置其孩子的約束為:BoxConstraints(0.0<=w<=411.4,0.0<=h<=683.4)。一個(gè)子widget RenderPadding進(jìn)一步插入這些約束以添加填充空間,padding值為EdgeInsets(16.0, 0.0, 16.0, 0.0),因此RenderConstrainedBox具有約束B(niǎo)oxConstraints(0.0<=w<=395.4, 0.0<=h<=667.4)。該creator字段告訴我們的這個(gè)對(duì)象可能是其FlatButton定義的一部分,它在其內(nèi)容上設(shè)置最小寬度為88像素,并且設(shè)置高度為36.0像素(這是Material Design設(shè)計(jì)規(guī)范中FlatButton類(lèi)的尺寸標(biāo)準(zhǔn))。

最內(nèi)部RenderPositionedBox再次松開(kāi)約束,這次是將按鈕中的文本居中。 在RenderParagraph中基于它的內(nèi)容來(lái)決定其大小。 如果您現(xiàn)在按照size鏈繼續(xù)往下查看,您會(huì)看到文本的大小是如何影響其按鈕的框的寬度的,它們都是根據(jù)孩子的尺寸自行調(diào)整大小。

另一種需要注意的是每個(gè)盒子描述的”relayoutSubtreeRoot”部分,它告訴你有多少祖先以某種方式依賴(lài)于這個(gè)元素的大小。 因此,RenderParagraph有一個(gè)relayoutSubtreeRoot=up8,這意味著當(dāng)它RenderParagraph被標(biāo)及為”dirty”時(shí),它的八個(gè)祖先也必須被標(biāo)記為”dirty”,因?yàn)樗鼈兛赡苁艿叫鲁叽绲挠绊憽?/p>

如果您編寫(xiě)自己的渲染對(duì)象,則可以通過(guò)覆蓋debugFillProperties()將信息添加到轉(zhuǎn)儲(chǔ)。 將DiagnosticsProperty對(duì)象作為方法的參數(shù),并調(diào)用父類(lèi)方法。

如果您嘗試調(diào)試合成問(wèn)題,則可以使用debugDumpLayerTree()。對(duì)于上面的例子,它會(huì)輸出:

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

這是根Layer的toStringDeep輸出的。

根部的變換是應(yīng)用設(shè)備像素比的變換; 在這種情況下,每個(gè)邏輯像素代表3.5個(gè)設(shè)備像素。

RepaintBoundary widget在渲染樹(shù)的層中創(chuàng)建了一個(gè)RenderRepaintBoundary。這用于減少需要重繪的需求量。

語(yǔ)義

您還可以調(diào)用debugDumpSemanticsTree()獲取語(yǔ)義樹(shù)(呈現(xiàn)給系統(tǒng)可訪(fǎng)問(wèn)性API的樹(shù))的轉(zhuǎn)儲(chǔ)。 要使用此功能,必須首先啟用輔助功能,例如啟用系統(tǒng)輔助工具或SemanticsDebugger (下面討論)。

對(duì)于上面的例子,它會(huì)輸出:

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")

調(diào)度

要找出相對(duì)于幀的開(kāi)始/結(jié)束事件發(fā)生的位置,可以切換debugPrintBeginFrameBanner和debugPrintEndFrameBanner布爾值以將幀的開(kāi)始和結(jié)束打印到控制臺(tái)。

例如:

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 : ????????????????????????????????????????????????????

debugPrintScheduleFrameStacks還可以用來(lái)打印導(dǎo)致當(dāng)前幀被調(diào)度的調(diào)用堆棧。

可視化調(diào)試

您也可以通過(guò)設(shè)置debugPaintSizeEnabled為true以可視方式調(diào)試布局問(wèn)題。 這是來(lái)自rendering庫(kù)的布爾值。它可以在任何時(shí)候啟用,并在為true時(shí)影響繪制。 設(shè)置它的最簡(jiǎn)單方法是在void main()的頂部設(shè)置。

當(dāng)它被啟用時(shí),所有的盒子都會(huì)得到一個(gè)明亮的深青色邊框,padding(來(lái)自widget如Padding)顯示為淺藍(lán)色,子widget周?chē)幸粋€(gè)深藍(lán)色框, 對(duì)齊方式(來(lái)自widget如Center和Align)顯示為黃色箭頭. 空白(如沒(méi)有任何子節(jié)點(diǎn)的Container)以灰色顯示。

debugPaintBaselinesEnabled做了類(lèi)似的事情,但對(duì)于具有基線(xiàn)的對(duì)象,文字基線(xiàn)以綠色顯示,表意(ideographic)基線(xiàn)以橙色顯示。

debugPaintPointersEnabled標(biāo)志打開(kāi)一個(gè)特殊模式,任何正在點(diǎn)擊的對(duì)象都會(huì)以深青色突出顯示。 這可以幫助您確定某個(gè)對(duì)象是否以某種不正確地方式進(jìn)行hit測(cè)試(Flutter檢測(cè)點(diǎn)擊的位置是否有能響應(yīng)用戶(hù)操作的widget),例如,如果它實(shí)際上超出了其父項(xiàng)的范圍,首先不會(huì)考慮通過(guò)hit測(cè)試。

如果您嘗試調(diào)試合成圖層,例如以確定是否以及在何處添加RepaintBoundary widget,則可以使用debugPaintLayerBordersEnabled 標(biāo)志, 該標(biāo)志用橙色或輪廓線(xiàn)標(biāo)出每個(gè)層的邊界,或者使用debugRepaintRainbowEnabled標(biāo)志, 只要他們重繪時(shí),這會(huì)使該層被一組旋轉(zhuǎn)色所覆蓋。

所有這些標(biāo)志只能在調(diào)試模式下工作。通常,F(xiàn)lutter框架中以“debug...” 開(kāi)頭的任何內(nèi)容都只能在調(diào)試模式下工作。

調(diào)試動(dòng)畫(huà)

調(diào)試動(dòng)畫(huà)最簡(jiǎn)單的方法是減慢它們的速度。為此,請(qǐng)將timeDilation變量(在scheduler庫(kù)中)設(shè)置為大于1.0的數(shù)字,例如50.0。 最好在應(yīng)用程序啟動(dòng)時(shí)只設(shè)置一次。如果您在運(yùn)行中更改它,尤其是在動(dòng)畫(huà)運(yùn)行時(shí)將其值減小,則框架的觀察時(shí)可能會(huì)倒退,這可能會(huì)導(dǎo)致斷言并且通常會(huì)干擾您的工作。

調(diào)試性能問(wèn)題

要了解您的應(yīng)用程序?qū)е轮匦虏季只蛑匦吕L制的原因,您可以分別設(shè)置debugPrintMarkNeedsLayoutStacks和 debugPrintMarkNeedsPaintStacks標(biāo)志。 每當(dāng)渲染盒被要求重新布局和重新繪制時(shí),這些都會(huì)將堆棧跟蹤記錄到控制臺(tái)。如果這種方法對(duì)您有用,您可以使用services庫(kù)中的debugPrintStack()方法按需打印堆棧痕跡。

衡量應(yīng)用啟動(dòng)時(shí)間

要收集有關(guān)Flutter應(yīng)用程序啟動(dòng)所需時(shí)間的詳細(xì)信息,可以在運(yùn)行flutter run時(shí)使用trace-startup和profile選項(xiàng)。

$ flutter run --trace-startup --profile

跟蹤輸出保存為start_up_info.json,在Flutter工程目錄在build目錄下。輸出列出了從應(yīng)用程序啟動(dòng)到這些跟蹤事件(以微秒捕獲)所用的時(shí)間:

  • 進(jìn)入Flutter引擎時(shí).
  • 展示應(yīng)用第一幀時(shí).
  • 初始化Flutter框架時(shí).
  • 完成Flutter框架初始化時(shí).

如 :

{
  "engineEnterTimestampMicros": 96025565262,
  "timeToFirstFrameMicros": 2171978,
  "timeToFrameworkInitMicros": 514585,
  "timeAfterFrameworkInitMicros": 1657393
}

跟蹤Dart代碼性能

要執(zhí)行自定義性能跟蹤和測(cè)量Dart任意代碼段的wall/CPU時(shí)間(類(lèi)似于在Android上使用systrace)。 使用dart:developer的Timeline工具來(lái)包含你想測(cè)試的代碼塊,例如:

Timeline.startSync('interesting function');
// iWonderHowLongThisTakes();
Timeline.finishSync();

然后打開(kāi)你應(yīng)用程序的Observatory timeline頁(yè)面,在”Recorded Streams”中選擇’Dart’復(fù)選框,并執(zhí)行你想測(cè)量的功能。

刷新頁(yè)面將在Chrome的跟蹤工具中顯示應(yīng)用按時(shí)間順序排列的timeline記錄。

請(qǐng)確保運(yùn)行flutter run時(shí)帶有--profile標(biāo)志,以確保運(yùn)行時(shí)性能特征與您的最終產(chǎn)品差異最小。

Performance Overlay

要獲得應(yīng)用程序性能圖,請(qǐng)將MaterialApp構(gòu)造函數(shù)的showPerformanceOverlay參數(shù)設(shè)置為true。 WidgetsApp構(gòu)造函數(shù)也有類(lèi)似的參數(shù)(如果你沒(méi)有使用MaterialApp或者WidgetsApp,你可以通過(guò)將你的應(yīng)用程序包裝在一個(gè)stack中, 并將一個(gè)widget放在通過(guò)new PerformanceOverlay.allEnabled()創(chuàng)建的stack上來(lái)獲得相同的效果)。

這將顯示兩個(gè)圖表。第一個(gè)是GPU線(xiàn)程花費(fèi)的時(shí)間,最后一個(gè)是CPU線(xiàn)程花費(fèi)的時(shí)間。 圖中的白線(xiàn)以16ms增量沿縱軸顯示; 如果圖中超過(guò)這三條線(xiàn)之一,那么您的運(yùn)行頻率低于60Hz。橫軸代表幀。 該圖僅在應(yīng)用程序繪制時(shí)更新,因此如果它處于空閑狀態(tài),該圖將停止移動(dòng)。

這應(yīng)該始終在發(fā)布模式(release mode)下測(cè)試,因?yàn)樵谡{(diào)試模式下,故意犧牲性能來(lái)?yè)Q取有助于開(kāi)發(fā)調(diào)試的功能,如assert聲明,這些都是非常耗時(shí)的,因此結(jié)果將會(huì)產(chǎn)生誤導(dǎo)。

Material grid

在開(kāi)發(fā)實(shí)現(xiàn)Material Design的應(yīng)用程序時(shí), 將Material Design基線(xiàn)網(wǎng)格覆蓋在應(yīng)用程序上可能有助于驗(yàn)證對(duì)齊。 為此,MaterialApp 構(gòu)造函數(shù) 有一個(gè)debugShowMaterialGrid參數(shù), 當(dāng)在調(diào)試模式設(shè)置為true時(shí),它將覆蓋這樣一個(gè)網(wǎng)格。

您也可以直接使用GridPaperwidget將這種網(wǎng)格覆蓋在非Material應(yīng)用程序上 。

以上內(nèi)容是否對(duì)您有幫助:
在線(xiàn)筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號(hào)
微信公眾號(hào)

編程獅公眾號(hào)