1// Copyright 2015 The Chromium Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4 5import 'dart:async'; 6import 'dart:developer' as developer; 7import 'dart:ui' show AppLifecycleState, Locale, AccessibilityFeatures, FrameTiming, TimingsCallback; 8 9import 'package:flutter/foundation.dart'; 10import 'package:flutter/gestures.dart'; 11import 'package:flutter/rendering.dart'; 12import 'package:flutter/scheduler.dart'; 13import 'package:flutter/services.dart'; 14 15import 'app.dart'; 16import 'debug.dart'; 17import 'focus_manager.dart'; 18import 'framework.dart'; 19import 'widget_inspector.dart'; 20 21export 'dart:ui' show AppLifecycleState, Locale; 22 23/// Interface for classes that register with the Widgets layer binding. 24/// 25/// When used as a mixin, provides no-op method implementations. 26/// 27/// See [WidgetsBinding.addObserver] and [WidgetsBinding.removeObserver]. 28/// 29/// This class can be extended directly, to get default behaviors for all of the 30/// handlers, or can used with the `implements` keyword, in which case all the 31/// handlers must be implemented (and the analyzer will list those that have 32/// been omitted). 33/// 34/// {@tool sample} 35/// 36/// This [StatefulWidget] implements the parts of the [State] and 37/// [WidgetsBindingObserver] protocols necessary to react to application 38/// lifecycle messages. See [didChangeAppLifecycleState]. 39/// 40/// ```dart 41/// class AppLifecycleReactor extends StatefulWidget { 42/// const AppLifecycleReactor({ Key key }) : super(key: key); 43/// 44/// @override 45/// _AppLifecycleReactorState createState() => _AppLifecycleReactorState(); 46/// } 47/// 48/// class _AppLifecycleReactorState extends State<AppLifecycleReactor> with WidgetsBindingObserver { 49/// @override 50/// void initState() { 51/// super.initState(); 52/// WidgetsBinding.instance.addObserver(this); 53/// } 54/// 55/// @override 56/// void dispose() { 57/// WidgetsBinding.instance.removeObserver(this); 58/// super.dispose(); 59/// } 60/// 61/// AppLifecycleState _notification; 62/// 63/// @override 64/// void didChangeAppLifecycleState(AppLifecycleState state) { 65/// setState(() { _notification = state; }); 66/// } 67/// 68/// @override 69/// Widget build(BuildContext context) { 70/// return Text('Last notification: $_notification'); 71/// } 72/// } 73/// ``` 74/// {@end-tool} 75/// 76/// To respond to other notifications, replace the [didChangeAppLifecycleState] 77/// method above with other methods from this class. 78abstract class WidgetsBindingObserver { 79 /// Called when the system tells the app to pop the current route. 80 /// For example, on Android, this is called when the user presses 81 /// the back button. 82 /// 83 /// Observers are notified in registration order until one returns 84 /// true. If none return true, the application quits. 85 /// 86 /// Observers are expected to return true if they were able to 87 /// handle the notification, for example by closing an active dialog 88 /// box, and false otherwise. The [WidgetsApp] widget uses this 89 /// mechanism to notify the [Navigator] widget that it should pop 90 /// its current route if possible. 91 /// 92 /// This method exposes the `popRoute` notification from 93 /// [SystemChannels.navigation]. 94 Future<bool> didPopRoute() => Future<bool>.value(false); 95 96 /// Called when the host tells the app to push a new route onto the 97 /// navigator. 98 /// 99 /// Observers are expected to return true if they were able to 100 /// handle the notification. Observers are notified in registration 101 /// order until one returns true. 102 /// 103 /// This method exposes the `pushRoute` notification from 104 /// [SystemChannels.navigation]. 105 Future<bool> didPushRoute(String route) => Future<bool>.value(false); 106 107 /// Called when the application's dimensions change. For example, 108 /// when a phone is rotated. 109 /// 110 /// This method exposes notifications from [Window.onMetricsChanged]. 111 /// 112 /// {@tool sample} 113 /// 114 /// This [StatefulWidget] implements the parts of the [State] and 115 /// [WidgetsBindingObserver] protocols necessary to react when the device is 116 /// rotated (or otherwise changes dimensions). 117 /// 118 /// ```dart 119 /// class MetricsReactor extends StatefulWidget { 120 /// const MetricsReactor({ Key key }) : super(key: key); 121 /// 122 /// @override 123 /// _MetricsReactorState createState() => _MetricsReactorState(); 124 /// } 125 /// 126 /// class _MetricsReactorState extends State<MetricsReactor> with WidgetsBindingObserver { 127 /// @override 128 /// void initState() { 129 /// super.initState(); 130 /// WidgetsBinding.instance.addObserver(this); 131 /// } 132 /// 133 /// @override 134 /// void dispose() { 135 /// WidgetsBinding.instance.removeObserver(this); 136 /// super.dispose(); 137 /// } 138 /// 139 /// Size _lastSize; 140 /// 141 /// @override 142 /// void didChangeMetrics() { 143 /// setState(() { _lastSize = WidgetsBinding.instance.window.physicalSize; }); 144 /// } 145 /// 146 /// @override 147 /// Widget build(BuildContext context) { 148 /// return Text('Current size: $_lastSize'); 149 /// } 150 /// } 151 /// ``` 152 /// {@end-tool} 153 /// 154 /// In general, this is unnecessary as the layout system takes care of 155 /// automatically recomputing the application geometry when the application 156 /// size changes. 157 /// 158 /// See also: 159 /// 160 /// * [MediaQuery.of], which provides a similar service with less 161 /// boilerplate. 162 void didChangeMetrics() { } 163 164 /// Called when the platform's text scale factor changes. 165 /// 166 /// This typically happens as the result of the user changing system 167 /// preferences, and it should affect all of the text sizes in the 168 /// application. 169 /// 170 /// This method exposes notifications from [Window.onTextScaleFactorChanged]. 171 /// 172 /// {@tool sample} 173 /// 174 /// ```dart 175 /// class TextScaleFactorReactor extends StatefulWidget { 176 /// const TextScaleFactorReactor({ Key key }) : super(key: key); 177 /// 178 /// @override 179 /// _TextScaleFactorReactorState createState() => _TextScaleFactorReactorState(); 180 /// } 181 /// 182 /// class _TextScaleFactorReactorState extends State<TextScaleFactorReactor> with WidgetsBindingObserver { 183 /// @override 184 /// void initState() { 185 /// super.initState(); 186 /// WidgetsBinding.instance.addObserver(this); 187 /// } 188 /// 189 /// @override 190 /// void dispose() { 191 /// WidgetsBinding.instance.removeObserver(this); 192 /// super.dispose(); 193 /// } 194 /// 195 /// double _lastTextScaleFactor; 196 /// 197 /// @override 198 /// void didChangeTextScaleFactor() { 199 /// setState(() { _lastTextScaleFactor = WidgetsBinding.instance.window.textScaleFactor; }); 200 /// } 201 /// 202 /// @override 203 /// Widget build(BuildContext context) { 204 /// return Text('Current scale factor: $_lastTextScaleFactor'); 205 /// } 206 /// } 207 /// ``` 208 /// {@end-tool} 209 /// 210 /// See also: 211 /// 212 /// * [MediaQuery.of], which provides a similar service with less 213 /// boilerplate. 214 void didChangeTextScaleFactor() { } 215 216 /// {@macro on_platform_brightness_change} 217 void didChangePlatformBrightness() { } 218 219 /// Called when the system tells the app that the user's locale has 220 /// changed. For example, if the user changes the system language 221 /// settings. 222 /// 223 /// This method exposes notifications from [Window.onLocaleChanged]. 224 void didChangeLocales(List<Locale> locale) { } 225 226 /// Called when the system puts the app in the background or returns 227 /// the app to the foreground. 228 /// 229 /// An example of implementing this method is provided in the class-level 230 /// documentation for the [WidgetsBindingObserver] class. 231 /// 232 /// This method exposes notifications from [SystemChannels.lifecycle]. 233 void didChangeAppLifecycleState(AppLifecycleState state) { } 234 235 /// Called when the system is running low on memory. 236 /// 237 /// This method exposes the `memoryPressure` notification from 238 /// [SystemChannels.system]. 239 void didHaveMemoryPressure() { } 240 241 /// Called when the system changes the set of currently active accessibility 242 /// features. 243 /// 244 /// This method exposes notifications from [Window.onAccessibilityFeaturesChanged]. 245 void didChangeAccessibilityFeatures() { } 246} 247 248/// The glue between the widgets layer and the Flutter engine. 249mixin WidgetsBinding on BindingBase, SchedulerBinding, GestureBinding, RendererBinding, SemanticsBinding { 250 @override 251 void initInstances() { 252 super.initInstances(); 253 _instance = this; 254 buildOwner.onBuildScheduled = _handleBuildScheduled; 255 window.onLocaleChanged = handleLocaleChanged; 256 window.onAccessibilityFeaturesChanged = handleAccessibilityFeaturesChanged; 257 SystemChannels.navigation.setMethodCallHandler(_handleNavigationInvocation); 258 SystemChannels.system.setMessageHandler(_handleSystemMessage); 259 FlutterErrorDetails.propertiesTransformers.add(transformDebugCreator); 260 } 261 262 /// The current [WidgetsBinding], if one has been created. 263 /// 264 /// If you need the binding to be constructed before calling [runApp], 265 /// you can ensure a Widget binding has been constructed by calling the 266 /// `WidgetsFlutterBinding.ensureInitialized()` function. 267 static WidgetsBinding get instance => _instance; 268 static WidgetsBinding _instance; 269 270 @override 271 void initServiceExtensions() { 272 super.initServiceExtensions(); 273 274 if (!kReleaseMode) { 275 registerSignalServiceExtension( 276 name: 'debugDumpApp', 277 callback: () { 278 debugDumpApp(); 279 return debugPrintDone; 280 }, 281 ); 282 283 registerBoolServiceExtension( 284 name: 'showPerformanceOverlay', 285 getter: () => 286 Future<bool>.value(WidgetsApp.showPerformanceOverlayOverride), 287 setter: (bool value) { 288 if (WidgetsApp.showPerformanceOverlayOverride == value) 289 return Future<void>.value(); 290 WidgetsApp.showPerformanceOverlayOverride = value; 291 return _forceRebuild(); 292 }, 293 ); 294 295 registerServiceExtension( 296 name: 'didSendFirstFrameEvent', 297 callback: (_) async { 298 return <String, dynamic>{ 299 // This is defined to return a STRING, not a boolean. 300 // Devtools, the Intellij plugin, and the flutter tool all depend 301 // on it returning a string and not a boolean. 302 'enabled': _needToReportFirstFrame ? 'false' : 'true', 303 }; 304 }, 305 ); 306 307 // This returns 'true' when the first frame is rasterized, and the trace 308 // event 'Rasterized first useful frame' is sent out. 309 registerServiceExtension( 310 name: 'didSendFirstFrameRasterizedEvent', 311 callback: (_) async { 312 return <String, dynamic>{ 313 // This is defined to return a STRING, not a boolean. 314 // Devtools, the Intellij plugin, and the flutter tool all depend 315 // on it returning a string and not a boolean. 316 'enabled': firstFrameRasterized ? 'true' : 'false', 317 }; 318 }, 319 ); 320 321 // Expose the ability to send Widget rebuilds as [Timeline] events. 322 registerBoolServiceExtension( 323 name: 'profileWidgetBuilds', 324 getter: () async => debugProfileBuildsEnabled, 325 setter: (bool value) async { 326 if (debugProfileBuildsEnabled != value) 327 debugProfileBuildsEnabled = value; 328 }, 329 ); 330 } 331 332 assert(() { 333 registerBoolServiceExtension( 334 name: 'debugAllowBanner', 335 getter: () => Future<bool>.value(WidgetsApp.debugAllowBannerOverride), 336 setter: (bool value) { 337 if (WidgetsApp.debugAllowBannerOverride == value) 338 return Future<void>.value(); 339 WidgetsApp.debugAllowBannerOverride = value; 340 return _forceRebuild(); 341 }, 342 ); 343 344 // This service extension is deprecated and will be removed by 12/1/2018. 345 // Use ext.flutter.inspector.show instead. 346 registerBoolServiceExtension( 347 name: 'debugWidgetInspector', 348 getter: () async => WidgetsApp.debugShowWidgetInspectorOverride, 349 setter: (bool value) { 350 if (WidgetsApp.debugShowWidgetInspectorOverride == value) 351 return Future<void>.value(); 352 WidgetsApp.debugShowWidgetInspectorOverride = value; 353 return _forceRebuild(); 354 }, 355 ); 356 357 WidgetInspectorService.instance.initServiceExtensions(registerServiceExtension); 358 359 return true; 360 }()); 361 } 362 363 Future<void> _forceRebuild() { 364 if (renderViewElement != null) { 365 buildOwner.reassemble(renderViewElement); 366 return endOfFrame; 367 } 368 return Future<void>.value(); 369 } 370 371 /// The [BuildOwner] in charge of executing the build pipeline for the 372 /// widget tree rooted at this binding. 373 BuildOwner get buildOwner => _buildOwner; 374 final BuildOwner _buildOwner = BuildOwner(); 375 376 /// The object in charge of the focus tree. 377 /// 378 /// Rarely used directly. Instead, consider using [FocusScope.of] to obtain 379 /// the [FocusScopeNode] for a given [BuildContext]. 380 /// 381 /// See [FocusManager] for more details. 382 FocusManager get focusManager => _buildOwner.focusManager; 383 384 final List<WidgetsBindingObserver> _observers = <WidgetsBindingObserver>[]; 385 386 /// Registers the given object as a binding observer. Binding 387 /// observers are notified when various application events occur, 388 /// for example when the system locale changes. Generally, one 389 /// widget in the widget tree registers itself as a binding 390 /// observer, and converts the system state into inherited widgets. 391 /// 392 /// For example, the [WidgetsApp] widget registers as a binding 393 /// observer and passes the screen size to a [MediaQuery] widget 394 /// each time it is built, which enables other widgets to use the 395 /// [MediaQuery.of] static method and (implicitly) the 396 /// [InheritedWidget] mechanism to be notified whenever the screen 397 /// size changes (e.g. whenever the screen rotates). 398 /// 399 /// See also: 400 /// 401 /// * [removeObserver], to release the resources reserved by this method. 402 /// * [WidgetsBindingObserver], which has an example of using this method. 403 void addObserver(WidgetsBindingObserver observer) => _observers.add(observer); 404 405 /// Unregisters the given observer. This should be used sparingly as 406 /// it is relatively expensive (O(N) in the number of registered 407 /// observers). 408 /// 409 /// See also: 410 /// 411 /// * [addObserver], for the method that adds observers in the first place. 412 /// * [WidgetsBindingObserver], which has an example of using this method. 413 bool removeObserver(WidgetsBindingObserver observer) => _observers.remove(observer); 414 415 @override 416 void handleMetricsChanged() { 417 super.handleMetricsChanged(); 418 for (WidgetsBindingObserver observer in _observers) 419 observer.didChangeMetrics(); 420 } 421 422 @override 423 void handleTextScaleFactorChanged() { 424 super.handleTextScaleFactorChanged(); 425 for (WidgetsBindingObserver observer in _observers) 426 observer.didChangeTextScaleFactor(); 427 } 428 429 @override 430 void handlePlatformBrightnessChanged() { 431 super.handlePlatformBrightnessChanged(); 432 for (WidgetsBindingObserver observer in _observers) 433 observer.didChangePlatformBrightness(); 434 } 435 436 @override 437 void handleAccessibilityFeaturesChanged() { 438 super.handleAccessibilityFeaturesChanged(); 439 for (WidgetsBindingObserver observer in _observers) 440 observer.didChangeAccessibilityFeatures(); 441 } 442 443 /// Called when the system locale changes. 444 /// 445 /// Calls [dispatchLocaleChanged] to notify the binding observers. 446 /// 447 /// See [Window.onLocaleChanged]. 448 @protected 449 @mustCallSuper 450 void handleLocaleChanged() { 451 dispatchLocalesChanged(window.locales); 452 } 453 454 /// Notify all the observers that the locale has changed (using 455 /// [WidgetsBindingObserver.didChangeLocales]), giving them the 456 /// `locales` argument. 457 /// 458 /// This is called by [handleLocaleChanged] when the [Window.onLocaleChanged] 459 /// notification is received. 460 @protected 461 @mustCallSuper 462 void dispatchLocalesChanged(List<Locale> locales) { 463 for (WidgetsBindingObserver observer in _observers) 464 observer.didChangeLocales(locales); 465 } 466 467 /// Notify all the observers that the active set of [AccessibilityFeatures] 468 /// has changed (using [WidgetsBindingObserver.didChangeAccessibilityFeatures]), 469 /// giving them the `features` argument. 470 /// 471 /// This is called by [handleAccessibilityFeaturesChanged] when the 472 /// [Window.onAccessibilityFeaturesChanged] notification is received. 473 @protected 474 @mustCallSuper 475 void dispatchAccessibilityFeaturesChanged() { 476 for (WidgetsBindingObserver observer in _observers) 477 observer.didChangeAccessibilityFeatures(); 478 } 479 480 /// Called when the system pops the current route. 481 /// 482 /// This first notifies the binding observers (using 483 /// [WidgetsBindingObserver.didPopRoute]), in registration order, until one 484 /// returns true, meaning that it was able to handle the request (e.g. by 485 /// closing a dialog box). If none return true, then the application is shut 486 /// down by calling [SystemNavigator.pop]. 487 /// 488 /// [WidgetsApp] uses this in conjunction with a [Navigator] to 489 /// cause the back button to close dialog boxes, return from modal 490 /// pages, and so forth. 491 /// 492 /// This method exposes the `popRoute` notification from 493 /// [SystemChannels.navigation]. 494 @protected 495 Future<void> handlePopRoute() async { 496 for (WidgetsBindingObserver observer in List<WidgetsBindingObserver>.from(_observers)) { 497 if (await observer.didPopRoute()) 498 return; 499 } 500 SystemNavigator.pop(); 501 } 502 503 /// Called when the host tells the app to push a new route onto the 504 /// navigator. 505 /// 506 /// This notifies the binding observers (using 507 /// [WidgetsBindingObserver.didPushRoute]), in registration order, until one 508 /// returns true, meaning that it was able to handle the request (e.g. by 509 /// opening a dialog box). If none return true, then nothing happens. 510 /// 511 /// This method exposes the `pushRoute` notification from 512 /// [SystemChannels.navigation]. 513 @protected 514 @mustCallSuper 515 Future<void> handlePushRoute(String route) async { 516 for (WidgetsBindingObserver observer in List<WidgetsBindingObserver>.from(_observers)) { 517 if (await observer.didPushRoute(route)) 518 return; 519 } 520 } 521 522 Future<dynamic> _handleNavigationInvocation(MethodCall methodCall) { 523 switch (methodCall.method) { 524 case 'popRoute': 525 return handlePopRoute(); 526 case 'pushRoute': 527 return handlePushRoute(methodCall.arguments); 528 } 529 return Future<dynamic>.value(); 530 } 531 532 @override 533 void handleAppLifecycleStateChanged(AppLifecycleState state) { 534 super.handleAppLifecycleStateChanged(state); 535 for (WidgetsBindingObserver observer in _observers) 536 observer.didChangeAppLifecycleState(state); 537 } 538 539 /// Called when the operating system notifies the application of a memory 540 /// pressure situation. 541 /// 542 /// Notifies all the observers using 543 /// [WidgetsBindingObserver.didHaveMemoryPressure]. 544 /// 545 /// This method exposes the `memoryPressure` notification from 546 /// [SystemChannels.system]. 547 void handleMemoryPressure() { 548 for (WidgetsBindingObserver observer in _observers) 549 observer.didHaveMemoryPressure(); 550 } 551 552 Future<void> _handleSystemMessage(Object systemMessage) async { 553 final Map<String, dynamic> message = systemMessage; 554 final String type = message['type']; 555 switch (type) { 556 case 'memoryPressure': 557 handleMemoryPressure(); 558 break; 559 } 560 return; 561 } 562 563 bool _needToReportFirstFrame = true; 564 int _deferFirstFrameReportCount = 0; 565 bool get _reportFirstFrame => _deferFirstFrameReportCount == 0; 566 567 568 final Completer<void> _firstFrameCompleter = Completer<void>(); 569 570 /// Whether the Flutter engine has rasterized the first frame. 571 /// 572 /// {@macro flutter.frame_rasterized_vs_presented} 573 /// 574 /// See also: 575 /// 576 /// * [waitUntilFirstFrameRasterized], the future when [firstFrameRasterized] 577 /// becomes true. 578 bool get firstFrameRasterized => _firstFrameCompleter.isCompleted; 579 580 /// A future that completes when the Flutter engine has rasterized the first 581 /// frame. 582 /// 583 /// {@macro flutter.frame_rasterize_vs_presented} 584 /// 585 /// See also: 586 /// 587 /// * [firstFrameRasterized], whether this future has completed or not. 588 Future<void> get waitUntilFirstFrameRasterized => _firstFrameCompleter.future; 589 590 /// Whether the first frame has finished building. 591 /// 592 /// Only useful in profile and debug builds; in release builds, this always 593 /// return false. This can be deferred using [deferFirstFrameReport] and 594 /// [allowFirstFrameReport]. The value is set at the end of the call to 595 /// [drawFrame]. 596 /// 597 /// This value can also be obtained over the VM service protocol as 598 /// `ext.flutter.didSendFirstFrameEvent`. 599 /// 600 /// See also: 601 /// 602 /// * [firstFrameRasterized], whether the first frame has finished rendering. 603 bool get debugDidSendFirstFrameEvent => !_needToReportFirstFrame; 604 605 /// Tell the framework not to report the frame it is building as a "useful" 606 /// first frame until there is a corresponding call to [allowFirstFrameReport]. 607 /// 608 /// This is used by [WidgetsApp] to avoid reporting frames that aren't useful 609 /// during startup as the "first frame". 610 void deferFirstFrameReport() { 611 if (!kReleaseMode) { 612 assert(_deferFirstFrameReportCount >= 0); 613 _deferFirstFrameReportCount += 1; 614 } 615 } 616 617 /// When called after [deferFirstFrameReport]: tell the framework to report 618 /// the frame it is building as a "useful" first frame. 619 /// 620 /// This method may only be called once for each corresponding call 621 /// to [deferFirstFrameReport]. 622 /// 623 /// This is used by [WidgetsApp] to report when the first useful frame is 624 /// painted. 625 void allowFirstFrameReport() { 626 if (!kReleaseMode) { 627 assert(_deferFirstFrameReportCount >= 1); 628 _deferFirstFrameReportCount -= 1; 629 } 630 } 631 632 void _handleBuildScheduled() { 633 // If we're in the process of building dirty elements, then changes 634 // should not trigger a new frame. 635 assert(() { 636 if (debugBuildingDirtyElements) { 637 throw FlutterError( 638 'Build scheduled during frame.\n' 639 'While the widget tree was being built, laid out, and painted, ' 640 'a new frame was scheduled to rebuild the widget tree. ' 641 'This might be because setState() was called from a layout or ' 642 'paint callback. ' 643 'If a change is needed to the widget tree, it should be applied ' 644 'as the tree is being built. Scheduling a change for the subsequent ' 645 'frame instead results in an interface that lags behind by one frame. ' 646 'If this was done to make your build dependent on a size measured at ' 647 'layout time, consider using a LayoutBuilder, CustomSingleChildLayout, ' 648 'or CustomMultiChildLayout. If, on the other hand, the one frame delay ' 649 'is the desired effect, for example because this is an ' 650 'animation, consider scheduling the frame in a post-frame callback ' 651 'using SchedulerBinding.addPostFrameCallback or ' 652 'using an AnimationController to trigger the animation.' 653 ); 654 } 655 return true; 656 }()); 657 ensureVisualUpdate(); 658 } 659 660 /// Whether we are currently in a frame. This is used to verify 661 /// that frames are not scheduled redundantly. 662 /// 663 /// This is public so that test frameworks can change it. 664 /// 665 /// This flag is not used in release builds. 666 @protected 667 bool debugBuildingDirtyElements = false; 668 669 /// Pump the build and rendering pipeline to generate a frame. 670 /// 671 /// This method is called by [handleDrawFrame], which itself is called 672 /// automatically by the engine when when it is time to lay out and paint a 673 /// frame. 674 /// 675 /// Each frame consists of the following phases: 676 /// 677 /// 1. The animation phase: The [handleBeginFrame] method, which is registered 678 /// with [Window.onBeginFrame], invokes all the transient frame callbacks 679 /// registered with [scheduleFrameCallback], in 680 /// registration order. This includes all the [Ticker] instances that are 681 /// driving [AnimationController] objects, which means all of the active 682 /// [Animation] objects tick at this point. 683 /// 684 /// 2. Microtasks: After [handleBeginFrame] returns, any microtasks that got 685 /// scheduled by transient frame callbacks get to run. This typically includes 686 /// callbacks for futures from [Ticker]s and [AnimationController]s that 687 /// completed this frame. 688 /// 689 /// After [handleBeginFrame], [handleDrawFrame], which is registered with 690 /// [Window.onDrawFrame], is called, which invokes all the persistent frame 691 /// callbacks, of which the most notable is this method, [drawFrame], which 692 /// proceeds as follows: 693 /// 694 /// 3. The build phase: All the dirty [Element]s in the widget tree are 695 /// rebuilt (see [State.build]). See [State.setState] for further details on 696 /// marking a widget dirty for building. See [BuildOwner] for more information 697 /// on this step. 698 /// 699 /// 4. The layout phase: All the dirty [RenderObject]s in the system are laid 700 /// out (see [RenderObject.performLayout]). See [RenderObject.markNeedsLayout] 701 /// for further details on marking an object dirty for layout. 702 /// 703 /// 5. The compositing bits phase: The compositing bits on any dirty 704 /// [RenderObject] objects are updated. See 705 /// [RenderObject.markNeedsCompositingBitsUpdate]. 706 /// 707 /// 6. The paint phase: All the dirty [RenderObject]s in the system are 708 /// repainted (see [RenderObject.paint]). This generates the [Layer] tree. See 709 /// [RenderObject.markNeedsPaint] for further details on marking an object 710 /// dirty for paint. 711 /// 712 /// 7. The compositing phase: The layer tree is turned into a [Scene] and 713 /// sent to the GPU. 714 /// 715 /// 8. The semantics phase: All the dirty [RenderObject]s in the system have 716 /// their semantics updated (see [RenderObject.assembleSemanticsNode]). This 717 /// generates the [SemanticsNode] tree. See 718 /// [RenderObject.markNeedsSemanticsUpdate] for further details on marking an 719 /// object dirty for semantics. 720 /// 721 /// For more details on steps 4-8, see [PipelineOwner]. 722 /// 723 /// 9. The finalization phase in the widgets layer: The widgets tree is 724 /// finalized. This causes [State.dispose] to be invoked on any objects that 725 /// were removed from the widgets tree this frame. See 726 /// [BuildOwner.finalizeTree] for more details. 727 /// 728 /// 10. The finalization phase in the scheduler layer: After [drawFrame] 729 /// returns, [handleDrawFrame] then invokes post-frame callbacks (registered 730 /// with [addPostFrameCallback]). 731 // 732 // When editing the above, also update rendering/binding.dart's copy. 733 @override 734 void drawFrame() { 735 assert(!debugBuildingDirtyElements); 736 assert(() { 737 debugBuildingDirtyElements = true; 738 return true; 739 }()); 740 741 if (_needToReportFirstFrame && _reportFirstFrame) { 742 assert(!_firstFrameCompleter.isCompleted); 743 // TODO(liyuqian): use a broadcast stream approach 744 final TimingsCallback oldCallback = WidgetsBinding.instance.window.onReportTimings; 745 WidgetsBinding.instance.window.onReportTimings = (List<FrameTiming> timings) { 746 if (!kReleaseMode) { 747 developer.Timeline.instantSync('Rasterized first useful frame'); 748 developer.postEvent('Flutter.FirstFrame', <String, dynamic>{}); 749 } 750 if (oldCallback != null) { 751 oldCallback(timings); 752 } 753 WidgetsBinding.instance.window.onReportTimings = oldCallback; 754 _firstFrameCompleter.complete(); 755 }; 756 } 757 758 try { 759 if (renderViewElement != null) 760 buildOwner.buildScope(renderViewElement); 761 super.drawFrame(); 762 buildOwner.finalizeTree(); 763 } finally { 764 assert(() { 765 debugBuildingDirtyElements = false; 766 return true; 767 }()); 768 } 769 if (!kReleaseMode) { 770 if (_needToReportFirstFrame && _reportFirstFrame) { 771 developer.Timeline.instantSync('Widgets built first useful frame'); 772 } 773 } 774 _needToReportFirstFrame = false; 775 } 776 777 /// The [Element] that is at the root of the hierarchy (and which wraps the 778 /// [RenderView] object at the root of the rendering hierarchy). 779 /// 780 /// This is initialized the first time [runApp] is called. 781 Element get renderViewElement => _renderViewElement; 782 Element _renderViewElement; 783 784 /// Takes a widget and attaches it to the [renderViewElement], creating it if 785 /// necessary. 786 /// 787 /// This is called by [runApp] to configure the widget tree. 788 /// 789 /// See also [RenderObjectToWidgetAdapter.attachToRenderTree]. 790 void attachRootWidget(Widget rootWidget) { 791 _renderViewElement = RenderObjectToWidgetAdapter<RenderBox>( 792 container: renderView, 793 debugShortDescription: '[root]', 794 child: rootWidget, 795 ).attachToRenderTree(buildOwner, renderViewElement); 796 } 797 798 /// Whether the [renderViewElement] has been initialized. 799 /// 800 /// This will be false until [runApp] is called (or [WidgetTester.pumpWidget] 801 /// is called in the context of a [TestWidgetsFlutterBinding]). 802 bool get isRootWidgetAttached => _renderViewElement != null; 803 804 @override 805 Future<void> performReassemble() { 806 assert(() { 807 WidgetInspectorService.instance.performReassemble(); 808 return true; 809 }()); 810 811 deferFirstFrameReport(); 812 if (renderViewElement != null) 813 buildOwner.reassemble(renderViewElement); 814 return super.performReassemble().then((void value) { 815 allowFirstFrameReport(); 816 }); 817 } 818} 819 820/// Inflate the given widget and attach it to the screen. 821/// 822/// The widget is given constraints during layout that force it to fill the 823/// entire screen. If you wish to align your widget to one side of the screen 824/// (e.g., the top), consider using the [Align] widget. If you wish to center 825/// your widget, you can also use the [Center] widget 826/// 827/// Calling [runApp] again will detach the previous root widget from the screen 828/// and attach the given widget in its place. The new widget tree is compared 829/// against the previous widget tree and any differences are applied to the 830/// underlying render tree, similar to what happens when a [StatefulWidget] 831/// rebuilds after calling [State.setState]. 832/// 833/// Initializes the binding using [WidgetsFlutterBinding] if necessary. 834/// 835/// See also: 836/// 837/// * [WidgetsBinding.attachRootWidget], which creates the root widget for the 838/// widget hierarchy. 839/// * [RenderObjectToWidgetAdapter.attachToRenderTree], which creates the root 840/// element for the element hierarchy. 841/// * [WidgetsBinding.handleBeginFrame], which pumps the widget pipeline to 842/// ensure the widget, element, and render trees are all built. 843void runApp(Widget app) { 844 WidgetsFlutterBinding.ensureInitialized() 845 ..attachRootWidget(app) 846 ..scheduleWarmUpFrame(); 847} 848 849/// Print a string representation of the currently running app. 850void debugDumpApp() { 851 assert(WidgetsBinding.instance != null); 852 String mode = 'RELEASE MODE'; 853 assert(() { mode = 'CHECKED MODE'; return true; }()); 854 debugPrint('${WidgetsBinding.instance.runtimeType} - $mode'); 855 if (WidgetsBinding.instance.renderViewElement != null) { 856 debugPrint(WidgetsBinding.instance.renderViewElement.toStringDeep()); 857 } else { 858 debugPrint('<no tree currently mounted>'); 859 } 860} 861 862/// A bridge from a [RenderObject] to an [Element] tree. 863/// 864/// The given container is the [RenderObject] that the [Element] tree should be 865/// inserted into. It must be a [RenderObject] that implements the 866/// [RenderObjectWithChildMixin] protocol. The type argument `T` is the kind of 867/// [RenderObject] that the container expects as its child. 868/// 869/// Used by [runApp] to bootstrap applications. 870class RenderObjectToWidgetAdapter<T extends RenderObject> extends RenderObjectWidget { 871 /// Creates a bridge from a [RenderObject] to an [Element] tree. 872 /// 873 /// Used by [WidgetsBinding] to attach the root widget to the [RenderView]. 874 RenderObjectToWidgetAdapter({ 875 this.child, 876 this.container, 877 this.debugShortDescription, 878 }) : super(key: GlobalObjectKey(container)); 879 880 /// The widget below this widget in the tree. 881 /// 882 /// {@macro flutter.widgets.child} 883 final Widget child; 884 885 /// The [RenderObject] that is the parent of the [Element] created by this widget. 886 final RenderObjectWithChildMixin<T> container; 887 888 /// A short description of this widget used by debugging aids. 889 final String debugShortDescription; 890 891 @override 892 RenderObjectToWidgetElement<T> createElement() => RenderObjectToWidgetElement<T>(this); 893 894 @override 895 RenderObjectWithChildMixin<T> createRenderObject(BuildContext context) => container; 896 897 @override 898 void updateRenderObject(BuildContext context, RenderObject renderObject) { } 899 900 /// Inflate this widget and actually set the resulting [RenderObject] as the 901 /// child of [container]. 902 /// 903 /// If `element` is null, this function will create a new element. Otherwise, 904 /// the given element will have an update scheduled to switch to this widget. 905 /// 906 /// Used by [runApp] to bootstrap applications. 907 RenderObjectToWidgetElement<T> attachToRenderTree(BuildOwner owner, [ RenderObjectToWidgetElement<T> element ]) { 908 if (element == null) { 909 owner.lockState(() { 910 element = createElement(); 911 assert(element != null); 912 element.assignOwner(owner); 913 }); 914 owner.buildScope(element, () { 915 element.mount(null, null); 916 }); 917 } else { 918 element._newWidget = this; 919 element.markNeedsBuild(); 920 } 921 return element; 922 } 923 924 @override 925 String toStringShort() => debugShortDescription ?? super.toStringShort(); 926} 927 928/// A [RootRenderObjectElement] that is hosted by a [RenderObject]. 929/// 930/// This element class is the instantiation of a [RenderObjectToWidgetAdapter] 931/// widget. It can be used only as the root of an [Element] tree (it cannot be 932/// mounted into another [Element]; it's parent must be null). 933/// 934/// In typical usage, it will be instantiated for a [RenderObjectToWidgetAdapter] 935/// whose container is the [RenderView] that connects to the Flutter engine. In 936/// this usage, it is normally instantiated by the bootstrapping logic in the 937/// [WidgetsFlutterBinding] singleton created by [runApp]. 938class RenderObjectToWidgetElement<T extends RenderObject> extends RootRenderObjectElement { 939 /// Creates an element that is hosted by a [RenderObject]. 940 /// 941 /// The [RenderObject] created by this element is not automatically set as a 942 /// child of the hosting [RenderObject]. To actually attach this element to 943 /// the render tree, call [RenderObjectToWidgetAdapter.attachToRenderTree]. 944 RenderObjectToWidgetElement(RenderObjectToWidgetAdapter<T> widget) : super(widget); 945 946 @override 947 RenderObjectToWidgetAdapter<T> get widget => super.widget; 948 949 Element _child; 950 951 static const Object _rootChildSlot = Object(); 952 953 @override 954 void visitChildren(ElementVisitor visitor) { 955 if (_child != null) 956 visitor(_child); 957 } 958 959 @override 960 void forgetChild(Element child) { 961 assert(child == _child); 962 _child = null; 963 } 964 965 @override 966 void mount(Element parent, dynamic newSlot) { 967 assert(parent == null); 968 super.mount(parent, newSlot); 969 _rebuild(); 970 } 971 972 @override 973 void update(RenderObjectToWidgetAdapter<T> newWidget) { 974 super.update(newWidget); 975 assert(widget == newWidget); 976 _rebuild(); 977 } 978 979 // When we are assigned a new widget, we store it here 980 // until we are ready to update to it. 981 Widget _newWidget; 982 983 @override 984 void performRebuild() { 985 if (_newWidget != null) { 986 // _newWidget can be null if, for instance, we were rebuilt 987 // due to a reassemble. 988 final Widget newWidget = _newWidget; 989 _newWidget = null; 990 update(newWidget); 991 } 992 super.performRebuild(); 993 assert(_newWidget == null); 994 } 995 996 void _rebuild() { 997 try { 998 _child = updateChild(_child, widget.child, _rootChildSlot); 999 assert(_child != null); 1000 } catch (exception, stack) { 1001 final FlutterErrorDetails details = FlutterErrorDetails( 1002 exception: exception, 1003 stack: stack, 1004 library: 'widgets library', 1005 context: ErrorDescription('attaching to the render tree'), 1006 ); 1007 FlutterError.reportError(details); 1008 final Widget error = ErrorWidget.builder(details); 1009 _child = updateChild(null, error, _rootChildSlot); 1010 } 1011 } 1012 1013 @override 1014 RenderObjectWithChildMixin<T> get renderObject => super.renderObject; 1015 1016 @override 1017 void insertChildRenderObject(RenderObject child, dynamic slot) { 1018 assert(slot == _rootChildSlot); 1019 assert(renderObject.debugValidateChild(child)); 1020 renderObject.child = child; 1021 } 1022 1023 @override 1024 void moveChildRenderObject(RenderObject child, dynamic slot) { 1025 assert(false); 1026 } 1027 1028 @override 1029 void removeChildRenderObject(RenderObject child) { 1030 assert(renderObject.child == child); 1031 renderObject.child = null; 1032 } 1033} 1034 1035/// A concrete binding for applications based on the Widgets framework. 1036/// 1037/// This is the glue that binds the framework to the Flutter engine. 1038class WidgetsFlutterBinding extends BindingBase with GestureBinding, ServicesBinding, SchedulerBinding, PaintingBinding, SemanticsBinding, RendererBinding, WidgetsBinding { 1039 1040 /// Returns an instance of the [WidgetsBinding], creating and 1041 /// initializing it if necessary. If one is created, it will be a 1042 /// [WidgetsFlutterBinding]. If one was previously initialized, then 1043 /// it will at least implement [WidgetsBinding]. 1044 /// 1045 /// You only need to call this method if you need the binding to be 1046 /// initialized before calling [runApp]. 1047 /// 1048 /// In the `flutter_test` framework, [testWidgets] initializes the 1049 /// binding instance to a [TestWidgetsFlutterBinding], not a 1050 /// [WidgetsFlutterBinding]. 1051 static WidgetsBinding ensureInitialized() { 1052 if (WidgetsBinding.instance == null) 1053 WidgetsFlutterBinding(); 1054 return WidgetsBinding.instance; 1055 } 1056} 1057